diff --git a/Source/Plugins/Plugin_Wiimote-testing/Plugin_Wiimote.vcproj b/Source/Plugins/Plugin_Wiimote-testing/Plugin_Wiimote.vcproj
new file mode 100644
index 0000000000..918bc36ffc
--- /dev/null
+++ b/Source/Plugins/Plugin_Wiimote-testing/Plugin_Wiimote.vcproj
@@ -0,0 +1,659 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Source/Plugins/Plugin_Wiimote-testing/Src/Config.cpp b/Source/Plugins/Plugin_Wiimote-testing/Src/Config.cpp
new file mode 100644
index 0000000000..be5d2cbe69
--- /dev/null
+++ b/Source/Plugins/Plugin_Wiimote-testing/Src/Config.cpp
@@ -0,0 +1,356 @@
+// Copyright (C) 2003-2008 Dolphin Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official SVN repository and contact information can be found at
+// http://code.google.com/p/dolphin-emu/
+
+
+#include
+
+#include "Common.h"
+#include "IniFile.h"
+#include "StringUtil.h"
+
+#include "Config.h"
+#include "EmuDefinitions.h" // for PadMapping
+#include "main.h"
+
+// TODO: Figure out what to do for non-Win32
+#ifndef _WIN32
+#define VK_LEFT 0
+#define VK_RIGHT 0
+#define VK_UP 0
+#define VK_DOWN 0
+#define VK_NUMPAD4 0
+#define VK_NUMPAD6 0
+#define VK_NUMPAD8 0
+#define VK_NUMPAD5 0
+#endif
+
+Config g_Config;
+
+Config::Config()
+{
+ // Set all default values to zero
+ memset(this, 0, sizeof(Config));
+}
+
+void Config::Load(bool ChangePad)
+{
+ std::string temp;
+ IniFile iniFile;
+ iniFile.Load(FULL_CONFIG_DIR "Wiimote.ini");
+
+ // General
+ iniFile.Get("Settings", "SidewaysDPad", &bSidewaysDPad, false);
+ iniFile.Get("Settings", "NunchuckConnected", &bNunchuckConnected, false);
+ iniFile.Get("Settings", "ClassicControllerConnected", &bClassicControllerConnected, false);
+
+ // Real Wiimote
+ iniFile.Get("Real", "Connect", &bConnectRealWiimote, true);
+ iniFile.Get("Real", "Use", &bUseRealWiimote, true);
+ iniFile.Get("Real", "UpdateStatus", &bUpdateRealWiimote, true);
+ iniFile.Get("Real", "AccNeutralX", &iAccNeutralX, 0);
+ iniFile.Get("Real", "AccNeutralY", &iAccNeutralY, 0);
+ iniFile.Get("Real", "AccNeutralZ", &iAccNeutralZ, 0);
+ iniFile.Get("Real", "AccNunNeutralX", &iAccNunNeutralX, 0);
+ iniFile.Get("Real", "AccNunNeutralY", &iAccNunNeutralY, 0);
+ iniFile.Get("Real", "AccNunNeutralZ", &iAccNunNeutralZ, 0);
+
+ // Default controls
+ int WmA = 65, WmB = 66,
+ Wm1 = 49, Wm2 = 50,
+ WmP = 80, WmM = 77, WmH = 72,
+ WmL = VK_LEFT, WmR = VK_RIGHT, WmU = VK_UP, WmD = VK_DOWN, // Regular directional keys
+ WmShake = 83, // S
+ WmPitchL = 51, WmPitchR = 52, // 3 and 4
+
+ NcZ = 90, NcC = 67, // C, Z
+ NcL = VK_NUMPAD4, NcR = VK_NUMPAD6, NcU = VK_NUMPAD8, NcD = VK_NUMPAD5, // Numpad
+ NcShake = 68, // D
+
+ CcA = 90, CcB = 67, CcX = 0x58, CcY = 0x59, // C, Z, X, Y
+ CcP = 0x4f, CcM = 0x4e, CcH = 0x55, // O instead of P, N instead of M, U instead of H
+ CcTl = 0x37, CcZl = 0x38, CcZr = 0x39, CcTr = 0x30, // 7, 8, 9, 0
+ CcDl = VK_NUMPAD4, CcDu = VK_NUMPAD8, CcDr = VK_NUMPAD6, CcDd = VK_NUMPAD5, // Numpad
+ CcLl = 0x4a, CcLu = 0x49, CcLr = 0x4c, CcLd = 0x4b, // J, I, L, K
+ CcRl = 0x44, CcRu = 0x52, CcRr = 0x47, CcRd = 0x46; // D, R, G, F
+
+ for (int i = 0; i < 1; i++)
+ {
+ // ==================================================================
+ // Slot specific settings
+ // ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
+ std::string SectionName = StringFromFormat("Wiimote%i", i + 1);
+ iniFile.Get(SectionName.c_str(), "NoTriggerFilter", &bNoTriggerFilter, false);
+ iniFile.Get(SectionName.c_str(), "TriggerType", &Trigger.Type, Trigger.TRIGGER_OFF);
+ iniFile.Get(SectionName.c_str(), "TriggerRollRange", &Trigger.Range.Roll, 50);
+ iniFile.Get(SectionName.c_str(), "TriggerPitchRange", &Trigger.Range.Pitch, false);
+
+ // Wiimote
+ iniFile.Get(SectionName.c_str(), "WmA", &WiiMoteEmu::PadMapping[i].Wm.A, WmA);
+ iniFile.Get(SectionName.c_str(), "WmB", &WiiMoteEmu::PadMapping[i].Wm.B, WmB);
+ iniFile.Get(SectionName.c_str(), "Wm1", &WiiMoteEmu::PadMapping[i].Wm.One, Wm1);
+ iniFile.Get(SectionName.c_str(), "Wm2", &WiiMoteEmu::PadMapping[i].Wm.Two, Wm2);
+ iniFile.Get(SectionName.c_str(), "WmP", &WiiMoteEmu::PadMapping[i].Wm.P, WmP);
+ iniFile.Get(SectionName.c_str(), "WmM", &WiiMoteEmu::PadMapping[i].Wm.M, WmM);
+ iniFile.Get(SectionName.c_str(), "WmH", &WiiMoteEmu::PadMapping[i].Wm.H, WmH);
+ iniFile.Get(SectionName.c_str(), "WmL", &WiiMoteEmu::PadMapping[i].Wm.L, WmL);
+ iniFile.Get(SectionName.c_str(), "WmR", &WiiMoteEmu::PadMapping[i].Wm.R, WmR);
+ iniFile.Get(SectionName.c_str(), "WmU", &WiiMoteEmu::PadMapping[i].Wm.U, WmU);
+ iniFile.Get(SectionName.c_str(), "WmD", &WiiMoteEmu::PadMapping[i].Wm.D, WmD);
+ iniFile.Get(SectionName.c_str(), "WmShake", &WiiMoteEmu::PadMapping[i].Wm.Shake, WmShake);
+ iniFile.Get(SectionName.c_str(), "WmPitchL", &WiiMoteEmu::PadMapping[i].Wm.PitchL, WmPitchL);
+ iniFile.Get(SectionName.c_str(), "WmPitchR", &WiiMoteEmu::PadMapping[i].Wm.PitchR, WmPitchR);
+
+ // Nunchuck
+ iniFile.Get(SectionName.c_str(), "NunchuckStick", &Nunchuck.Type, Nunchuck.KEYBOARD);
+ iniFile.Get(SectionName.c_str(), "NcZ", &WiiMoteEmu::PadMapping[i].Nc.Z, NcZ);
+ iniFile.Get(SectionName.c_str(), "NcC", &WiiMoteEmu::PadMapping[i].Nc.C, NcC);
+ iniFile.Get(SectionName.c_str(), "NcL", &WiiMoteEmu::PadMapping[i].Nc.L, NcL);
+ iniFile.Get(SectionName.c_str(), "NcR", &WiiMoteEmu::PadMapping[i].Nc.R, NcR);
+ iniFile.Get(SectionName.c_str(), "NcU", &WiiMoteEmu::PadMapping[i].Nc.U, NcU);
+ iniFile.Get(SectionName.c_str(), "NcD", &WiiMoteEmu::PadMapping[i].Nc.D, NcD);
+ iniFile.Get(SectionName.c_str(), "NcShake", &WiiMoteEmu::PadMapping[i].Nc.Shake, NcShake);
+
+ // Classic Controller
+ iniFile.Get(SectionName.c_str(), "CcLeftStick", &ClassicController.LType, ClassicController.KEYBOARD);
+ iniFile.Get(SectionName.c_str(), "CcRightStick", &ClassicController.RType, ClassicController.KEYBOARD);
+ iniFile.Get(SectionName.c_str(), "CcTriggers", &ClassicController.TType, ClassicController.KEYBOARD);
+ iniFile.Get(SectionName.c_str(), "CcA", &WiiMoteEmu::PadMapping[i].Cc.A, CcA);
+ iniFile.Get(SectionName.c_str(), "CcB", &WiiMoteEmu::PadMapping[i].Cc.B, CcB);
+ iniFile.Get(SectionName.c_str(), "CcX", &WiiMoteEmu::PadMapping[i].Cc.X, CcX);
+ iniFile.Get(SectionName.c_str(), "CcY", &WiiMoteEmu::PadMapping[i].Cc.Y, CcY);
+ iniFile.Get(SectionName.c_str(), "CcP", &WiiMoteEmu::PadMapping[i].Cc.P, CcP);
+ iniFile.Get(SectionName.c_str(), "CcM", &WiiMoteEmu::PadMapping[i].Cc.M, CcM);
+ iniFile.Get(SectionName.c_str(), "CcH", &WiiMoteEmu::PadMapping[i].Cc.H, CcH);
+ iniFile.Get(SectionName.c_str(), "CcTl", &WiiMoteEmu::PadMapping[i].Cc.Tl, CcTl);
+ iniFile.Get(SectionName.c_str(), "CcZl", &WiiMoteEmu::PadMapping[i].Cc.Zl, CcZl);
+ iniFile.Get(SectionName.c_str(), "CcZr", &WiiMoteEmu::PadMapping[i].Cc.Zr, CcZr);
+ iniFile.Get(SectionName.c_str(), "CcTr", &WiiMoteEmu::PadMapping[i].Cc.Tr, CcTr);
+ iniFile.Get(SectionName.c_str(), "CcDl", &WiiMoteEmu::PadMapping[i].Cc.Dl, CcDl);
+ iniFile.Get(SectionName.c_str(), "CcDu", &WiiMoteEmu::PadMapping[i].Cc.Du, CcDu);
+ iniFile.Get(SectionName.c_str(), "CcDr", &WiiMoteEmu::PadMapping[i].Cc.Dr, CcDr);
+ iniFile.Get(SectionName.c_str(), "CcDd", &WiiMoteEmu::PadMapping[i].Cc.Dd, CcDd);
+ iniFile.Get(SectionName.c_str(), "CcLl", &WiiMoteEmu::PadMapping[i].Cc.Ll, CcLl);
+ iniFile.Get(SectionName.c_str(), "CcLu", &WiiMoteEmu::PadMapping[i].Cc.Lu, CcLu);
+ iniFile.Get(SectionName.c_str(), "CcLr", &WiiMoteEmu::PadMapping[i].Cc.Lr, CcLr);
+ iniFile.Get(SectionName.c_str(), "CcLd", &WiiMoteEmu::PadMapping[i].Cc.Ld, CcLd);
+ iniFile.Get(SectionName.c_str(), "CcRl", &WiiMoteEmu::PadMapping[i].Cc.Rl, CcRl);
+ iniFile.Get(SectionName.c_str(), "CcRu", &WiiMoteEmu::PadMapping[i].Cc.Ru, CcRu);
+ iniFile.Get(SectionName.c_str(), "CcRr", &WiiMoteEmu::PadMapping[i].Cc.Rr, CcRr);
+ iniFile.Get(SectionName.c_str(), "CcRd", &WiiMoteEmu::PadMapping[i].Cc.Rd, CcRd);
+
+ // Don't update this when we are loading settings from the ConfigBox
+ if(!ChangePad)
+ {
+ /* This pad Id could possibly be higher than the number of pads that are connected,
+ but we check later, when needed, that that is not the case */
+ iniFile.Get(SectionName.c_str(), "DeviceID", &WiiMoteEmu::PadMapping[i].ID, 0);
+ iniFile.Get(SectionName.c_str(), "Enabled", &WiiMoteEmu::PadMapping[i].enabled, true);
+ }
+ // ===================
+
+ // ==================================================================
+ // Joypad specific settings
+ // ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
+ // Current joypad device ID: PadMapping[i].ID
+ // Current joypad name: joyinfo[PadMapping[i].ID].Name
+
+ /* Prevent a crash from illegal access to joyinfo that will only have values for
+ the current amount of connected PadMapping */
+ if((u32)WiiMoteEmu::PadMapping[i].ID >= WiiMoteEmu::joyinfo.size()) continue;
+
+ // Create a section name
+ SectionName = WiiMoteEmu::joyinfo[WiiMoteEmu::PadMapping[i].ID].Name;
+
+ iniFile.Get(SectionName.c_str(), "left_x", &WiiMoteEmu::PadMapping[i].Axis.Lx, 0);
+ iniFile.Get(SectionName.c_str(), "left_y", &WiiMoteEmu::PadMapping[i].Axis.Ly, 1);
+ iniFile.Get(SectionName.c_str(), "right_x", &WiiMoteEmu::PadMapping[i].Axis.Rx, 2);
+ iniFile.Get(SectionName.c_str(), "right_y", &WiiMoteEmu::PadMapping[i].Axis.Ry, 3);
+ iniFile.Get(SectionName.c_str(), "l_trigger", &WiiMoteEmu::PadMapping[i].Axis.Tl, 1004);
+ iniFile.Get(SectionName.c_str(), "r_trigger", &WiiMoteEmu::PadMapping[i].Axis.Tr, 1005);
+ iniFile.Get(SectionName.c_str(), "DeadZoneL", &WiiMoteEmu::PadMapping[i].DeadZoneL, 0);
+ iniFile.Get(SectionName.c_str(), "DeadZoneR", &WiiMoteEmu::PadMapping[i].DeadZoneR, 0);
+ iniFile.Get(SectionName.c_str(), "TriggerType", &WiiMoteEmu::PadMapping[i].triggertype, 0);
+ iniFile.Get(SectionName.c_str(), "Diagonal", &WiiMoteEmu::PadMapping[i].SDiagonal, "100%");
+ iniFile.Get(SectionName.c_str(), "Circle2Square", &WiiMoteEmu::PadMapping[i].bCircle2Square, false);
+ iniFile.Get(SectionName.c_str(), "RollInvert", &WiiMoteEmu::PadMapping[i].bRollInvert, false);
+ iniFile.Get(SectionName.c_str(), "PitchInvert", &WiiMoteEmu::PadMapping[i].bPitchInvert, false);
+ }
+ // =============================
+
+ // ==================================================================
+ // Load the IR cursor settings if it's avaliable, if not load the default settings
+ // ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
+ iniFile.Load(FULL_CONFIG_DIR "IR Pointer.ini");
+ std::string TmpSection;
+ if (g_ISOId) TmpSection = Hex2Ascii(g_ISOId); else TmpSection = "Default";
+ iniFile.Get(TmpSection.c_str(), "IRLeft", &iIRLeft, LEFT);
+ iniFile.Get(TmpSection.c_str(), "IRTop", &iIRTop, TOP);
+ iniFile.Get(TmpSection.c_str(), "IRWidth", &iIRWidth, RIGHT - LEFT);
+ iniFile.Get(TmpSection.c_str(), "IRHeight", &iIRHeight, BOTTOM - TOP);
+ // =============================
+
+ // ==================================================================
+ /* Load a few screen settings to. If these are added to the DirectX plugin it's probably
+ better to place them in the main Dolphin.ini file */
+ // ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
+ iniFile.Load(FULL_CONFIG_DIR "gfx_opengl.ini");
+ iniFile.Get("Settings", "KeepAR_4_3", &bKeepAR43, false);
+ iniFile.Get("Settings", "KeepAR_16_9", &bKeepAR169, false);
+ iniFile.Get("Settings", "Crop", &bCrop, false);
+ // =============================
+
+ // Logging
+ INFO_LOG(CONSOLE, "Load()\n");
+}
+
+void Config::Save(int Slot)
+{
+ IniFile iniFile;
+ iniFile.Load(FULL_CONFIG_DIR "Wiimote.ini");
+ iniFile.Set("Settings", "SidewaysDPad", bSidewaysDPad);
+ iniFile.Set("Settings", "NunchuckConnected", bNunchuckConnected);
+ iniFile.Set("Settings", "ClassicControllerConnected", bClassicControllerConnected);
+
+ iniFile.Set("Real", "Connect", bConnectRealWiimote);
+ iniFile.Set("Real", "Use", bUseRealWiimote);
+ iniFile.Set("Real", "UpdateStatus", bUpdateRealWiimote);
+ iniFile.Set("Real", "AccNeutralX", iAccNeutralX);
+ iniFile.Set("Real", "AccNeutralY", iAccNeutralY);
+ iniFile.Set("Real", "AccNeutralZ", iAccNeutralZ);
+ iniFile.Set("Real", "AccNunNeutralX", iAccNunNeutralX);
+ iniFile.Set("Real", "AccNunNeutralY", iAccNunNeutralY);
+ iniFile.Set("Real", "AccNunNeutralZ", iAccNunNeutralZ);
+
+ for (int i = 0; i < 1; i++)
+ {
+ // ==================================================================
+ // Slot specific settings
+ // ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
+ std::string SectionName = StringFromFormat("Wiimote%i", i + 1);
+ iniFile.Set(SectionName.c_str(), "Enabled", WiiMoteEmu::PadMapping[i].enabled);
+ iniFile.Set(SectionName.c_str(), "NoTriggerFilter", bNoTriggerFilter);
+ iniFile.Set(SectionName.c_str(), "TriggerType", Trigger.Type);
+ iniFile.Set(SectionName.c_str(), "TriggerRollRange", Trigger.Range.Roll);
+ iniFile.Set(SectionName.c_str(), "TriggerPitchRange", Trigger.Range.Pitch);
+
+ // Wiimote
+ iniFile.Set(SectionName.c_str(), "WmA", WiiMoteEmu::PadMapping[i].Wm.A);
+ iniFile.Set(SectionName.c_str(), "WmB", WiiMoteEmu::PadMapping[i].Wm.B);
+ iniFile.Set(SectionName.c_str(), "Wm1", WiiMoteEmu::PadMapping[i].Wm.One);
+ iniFile.Set(SectionName.c_str(), "Wm2", WiiMoteEmu::PadMapping[i].Wm.Two);
+ iniFile.Set(SectionName.c_str(), "WmP", WiiMoteEmu::PadMapping[i].Wm.P);
+ iniFile.Set(SectionName.c_str(), "WmM", WiiMoteEmu::PadMapping[i].Wm.M);
+ iniFile.Set(SectionName.c_str(), "WmH", WiiMoteEmu::PadMapping[i].Wm.H);
+ iniFile.Set(SectionName.c_str(), "WmL", WiiMoteEmu::PadMapping[i].Wm.L);
+ iniFile.Set(SectionName.c_str(), "WmR", WiiMoteEmu::PadMapping[i].Wm.R);
+ iniFile.Set(SectionName.c_str(), "WmU", WiiMoteEmu::PadMapping[i].Wm.U);
+ iniFile.Set(SectionName.c_str(), "WmD", WiiMoteEmu::PadMapping[i].Wm.D);
+ iniFile.Set(SectionName.c_str(), "WmShake", WiiMoteEmu::PadMapping[i].Wm.Shake);
+ iniFile.Set(SectionName.c_str(), "WmPitchL", WiiMoteEmu::PadMapping[i].Wm.PitchL);
+ iniFile.Set(SectionName.c_str(), "WmPitchR", WiiMoteEmu::PadMapping[i].Wm.PitchR);
+
+ // Nunchuck
+ iniFile.Set(SectionName.c_str(), "NunchuckStick", Nunchuck.Type);
+ iniFile.Set(SectionName.c_str(), "NcZ", WiiMoteEmu::PadMapping[i].Nc.Z);
+ iniFile.Set(SectionName.c_str(), "NcC", WiiMoteEmu::PadMapping[i].Nc.C);
+ iniFile.Set(SectionName.c_str(), "NcL", WiiMoteEmu::PadMapping[i].Nc.L);
+ iniFile.Set(SectionName.c_str(), "NcR", WiiMoteEmu::PadMapping[i].Nc.R);
+ iniFile.Set(SectionName.c_str(), "NcU", WiiMoteEmu::PadMapping[i].Nc.U);
+ iniFile.Set(SectionName.c_str(), "NcD", WiiMoteEmu::PadMapping[i].Nc.D);
+ iniFile.Set(SectionName.c_str(), "NcShake", WiiMoteEmu::PadMapping[i].Nc.Shake);
+
+ // Classic Controller
+ iniFile.Set(SectionName.c_str(), "CcLeftStick", ClassicController.LType);
+ iniFile.Set(SectionName.c_str(), "CcRightStick", ClassicController.RType);
+ iniFile.Set(SectionName.c_str(), "CcTriggers", ClassicController.TType);
+ iniFile.Set(SectionName.c_str(), "CcA", WiiMoteEmu::PadMapping[i].Cc.A);
+ iniFile.Set(SectionName.c_str(), "CcB", WiiMoteEmu::PadMapping[i].Cc.B);
+ iniFile.Set(SectionName.c_str(), "CcX", WiiMoteEmu::PadMapping[i].Cc.X);
+ iniFile.Set(SectionName.c_str(), "CcY", WiiMoteEmu::PadMapping[i].Cc.Y);
+ iniFile.Set(SectionName.c_str(), "CcP", WiiMoteEmu::PadMapping[i].Cc.P);
+ iniFile.Set(SectionName.c_str(), "CcM", WiiMoteEmu::PadMapping[i].Cc.M);
+ iniFile.Set(SectionName.c_str(), "CcH", WiiMoteEmu::PadMapping[i].Cc.H);
+ iniFile.Set(SectionName.c_str(), "CcTl", WiiMoteEmu::PadMapping[i].Cc.Tl);
+ iniFile.Set(SectionName.c_str(), "CcZl", WiiMoteEmu::PadMapping[i].Cc.Zl);
+ iniFile.Set(SectionName.c_str(), "CcZr", WiiMoteEmu::PadMapping[i].Cc.Zr);
+ iniFile.Set(SectionName.c_str(), "CcTr", WiiMoteEmu::PadMapping[i].Cc.Tr);
+ iniFile.Set(SectionName.c_str(), "CcDl", WiiMoteEmu::PadMapping[i].Cc.Dl);
+ iniFile.Set(SectionName.c_str(), "CcDu", WiiMoteEmu::PadMapping[i].Cc.Du);
+ iniFile.Set(SectionName.c_str(), "CcDr", WiiMoteEmu::PadMapping[i].Cc.Dr);
+ iniFile.Set(SectionName.c_str(), "CcDd", WiiMoteEmu::PadMapping[i].Cc.Dd);
+ iniFile.Set(SectionName.c_str(), "CcLl", WiiMoteEmu::PadMapping[i].Cc.Ll);
+ iniFile.Set(SectionName.c_str(), "CcLu", WiiMoteEmu::PadMapping[i].Cc.Lu);
+ iniFile.Set(SectionName.c_str(), "CcLr", WiiMoteEmu::PadMapping[i].Cc.Lr);
+ iniFile.Set(SectionName.c_str(), "CcLd", WiiMoteEmu::PadMapping[i].Cc.Ld);
+ iniFile.Set(SectionName.c_str(), "CcRl", WiiMoteEmu::PadMapping[i].Cc.Rl);
+ iniFile.Set(SectionName.c_str(), "CcRu", WiiMoteEmu::PadMapping[i].Cc.Ru);
+ iniFile.Set(SectionName.c_str(), "CcRr", WiiMoteEmu::PadMapping[i].Cc.Rr);
+ iniFile.Set(SectionName.c_str(), "CcRd", WiiMoteEmu::PadMapping[i].Cc.Rd);
+
+ // Save the physical device ID number
+ iniFile.Set(SectionName.c_str(), "DeviceID", WiiMoteEmu::PadMapping[i].ID);
+ // ===================
+
+ // ==================================================================
+ // Joypad specific settings
+ // ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
+ // Current joypad device ID: PadMapping[i].ID
+ // Current joypad name: joyinfo[PadMapping[i].ID].Name
+
+ /* Save joypad specific settings. Check for "PadMapping[i].ID < SDL_NumJoysticks()" to
+ avoid reading a joyinfo that does't exist */
+ if((u32)WiiMoteEmu::PadMapping[i].ID >= WiiMoteEmu::joyinfo.size()) continue;
+
+ // Create a new section name after the joypad name
+ SectionName = WiiMoteEmu::joyinfo[WiiMoteEmu::PadMapping[i].ID].Name;
+
+ iniFile.Set(SectionName.c_str(), "left_x", WiiMoteEmu::PadMapping[i].Axis.Lx);
+ iniFile.Set(SectionName.c_str(), "left_y", WiiMoteEmu::PadMapping[i].Axis.Ly);
+ iniFile.Set(SectionName.c_str(), "right_x", WiiMoteEmu::PadMapping[i].Axis.Rx);
+ iniFile.Set(SectionName.c_str(), "right_y", WiiMoteEmu::PadMapping[i].Axis.Ry);
+ iniFile.Set(SectionName.c_str(), "l_trigger", WiiMoteEmu::PadMapping[i].Axis.Tl);
+ iniFile.Set(SectionName.c_str(), "r_trigger", WiiMoteEmu::PadMapping[i].Axis.Tr);
+
+ iniFile.Set(SectionName.c_str(), "DeadZoneL", WiiMoteEmu::PadMapping[i].DeadZoneL);
+ iniFile.Set(SectionName.c_str(), "DeadZoneR", WiiMoteEmu::PadMapping[i].DeadZoneR);
+ //iniFile.Set(SectionName.c_str(), "controllertype", WiiMoteEmu::PadMapping[i].controllertype);
+ iniFile.Set(SectionName.c_str(), "TriggerType", WiiMoteEmu::PadMapping[i].triggertype);
+ iniFile.Set(SectionName.c_str(), "Diagonal", WiiMoteEmu::PadMapping[i].SDiagonal);
+ iniFile.Set(SectionName.c_str(), "Circle2Square", WiiMoteEmu::PadMapping[i].bCircle2Square);
+ iniFile.Set(SectionName.c_str(), "RollInvert", WiiMoteEmu::PadMapping[i].bRollInvert);
+ iniFile.Set(SectionName.c_str(), "PitchInvert", WiiMoteEmu::PadMapping[i].bPitchInvert);
+ // ======================================
+ }
+
+ iniFile.Save(FULL_CONFIG_DIR "Wiimote.ini");
+
+ // ==================================================================
+ // Save the IR cursor settings if it's avaliable, if not save the default settings
+ // ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
+ iniFile.Load(FULL_CONFIG_DIR "IR Pointer.ini");
+ std::string TmpSection;
+ if (g_ISOId) TmpSection = Hex2Ascii(g_ISOId); else TmpSection = "Default";
+ iniFile.Set(TmpSection.c_str(), "IRLeft", iIRLeft);
+ iniFile.Set(TmpSection.c_str(), "IRTop", iIRTop);
+ iniFile.Set(TmpSection.c_str(), "IRWidth", iIRWidth);
+ iniFile.Set(TmpSection.c_str(), "IRHeight", iIRHeight);
+ iniFile.Save(FULL_CONFIG_DIR "IR Pointer.ini");
+ // =============================
+
+ // Logging
+ INFO_LOG(CONSOLE, "Save()\n");
+}
diff --git a/Source/Plugins/Plugin_Wiimote-testing/Src/Config.h b/Source/Plugins/Plugin_Wiimote-testing/Src/Config.h
new file mode 100644
index 0000000000..03018c384f
--- /dev/null
+++ b/Source/Plugins/Plugin_Wiimote-testing/Src/Config.h
@@ -0,0 +1,94 @@
+// Copyright (C) 2003-2009 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 _PLUGIN_WIIMOTE_CONFIG_H
+#define _PLUGIN_WIIMOTE_CONFIG_H
+
+
+struct Config
+{
+ Config();
+ void Load(bool ChangePad = false);
+ void Save(int Slot = -1);
+
+ struct PadRange
+ {
+ int Roll;
+ int Pitch;
+ };
+
+ struct PadTrigger
+ {
+ enum ETriggerType
+ {
+ TRIGGER_OFF = 0,
+ KEYBOARD,
+ ANALOG1,
+ ANALOG2,
+ TRIGGER
+ };
+ int Type;
+ PadRange Range;
+ };
+ struct PadNunchuck
+ {
+ enum ENunchuckStick
+ {
+ KEYBOARD,
+ ANALOG1,
+ ANALOG2
+ };
+ int Type;
+ };
+ struct PadClassicController
+ {
+ enum ECcStick
+ {
+ KEYBOARD,
+ ANALOG1,
+ ANALOG2,
+ TRIGGER
+ };
+ int LType;
+ int RType;
+ int TType;
+ };
+
+ // Emulated Wiimote
+ bool bSidewaysDPad;
+ bool bWideScreen;
+ bool bNunchuckConnected, bClassicControllerConnected;
+
+ // Real Wiimote
+ bool bConnectRealWiimote, bUseRealWiimote, bUpdateRealWiimote;
+ int iIRLeft, iIRTop, iIRWidth, iIRHeight;
+ int iAccNeutralX, iAccNeutralY, iAccNeutralZ;
+ int iAccNunNeutralX, iAccNunNeutralY, iAccNunNeutralZ;
+
+ // Gamepad
+ bool bNoTriggerFilter;
+ PadTrigger Trigger;
+ PadNunchuck Nunchuck;
+ PadClassicController ClassicController;
+
+ // Screen size settings
+ bool bKeepAR43, bKeepAR169, bCrop;
+};
+
+extern Config g_Config;
+
+#endif // _PLUGIN_WIIMOTE_CONFIG_H
diff --git a/Source/Plugins/Plugin_Wiimote-testing/Src/ConfigDlg.cpp b/Source/Plugins/Plugin_Wiimote-testing/Src/ConfigDlg.cpp
new file mode 100644
index 0000000000..7f4456d84a
--- /dev/null
+++ b/Source/Plugins/Plugin_Wiimote-testing/Src/ConfigDlg.cpp
@@ -0,0 +1,1760 @@
+// Copyright (C) 2003-2008 Dolphin Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official SVN repository and contact information can be found at
+// http://code.google.com/p/dolphin-emu/
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Includes
+// ŻŻŻŻŻŻŻŻŻŻŻŻŻ
+//#include "Common.h" // for u16
+#include "CommonTypes.h" // for u16
+#include "IniFile.h"
+#include "Timer.h"
+#include "StringUtil.h"
+
+#include "wiimote_real.h" // Local
+#include "wiimote_hid.h"
+#include "main.h"
+#include "ConfigDlg.h"
+#include "Config.h"
+#include "EmuMain.h" // for LoadRecordedMovements()
+#include "EmuSubroutines.h" // for WmRequestStatus
+#include "EmuDefinitions.h" // for joyinfo
+//////////////////////////////////////
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Variables
+// ----------------
+// Trigger Type
+enum
+{
+ CTL_TRIGGER_SDL = 0, //
+ CTL_TRIGGER_XINPUT // The XBox 360 pad
+};
+//////////////////////////////////////
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Event table
+// ŻŻŻŻŻŻŻŻŻŻŻŻŻ
+BEGIN_EVENT_TABLE(ConfigDialog,wxDialog)
+ EVT_CLOSE(ConfigDialog::OnClose)
+ EVT_BUTTON(ID_CLOSE, ConfigDialog::CloseClick)
+ EVT_BUTTON(ID_APPLY, ConfigDialog::CloseClick)
+ EVT_BUTTON(ID_ABOUTOGL, ConfigDialog::AboutClick)
+
+ EVT_CHECKBOX(ID_SIDEWAYSDPAD, ConfigDialog::GeneralSettingsChanged)
+ EVT_CHECKBOX(ID_NUNCHUCKCONNECTED, ConfigDialog::GeneralSettingsChanged)
+ EVT_CHECKBOX(ID_CLASSICCONTROLLERCONNECTED, ConfigDialog::GeneralSettingsChanged)
+
+ EVT_CHECKBOX(ID_CONNECT_REAL, ConfigDialog::GeneralSettingsChanged)
+ EVT_CHECKBOX(ID_USE_REAL, ConfigDialog::GeneralSettingsChanged)
+ EVT_CHECKBOX(ID_UPDATE_REAL, ConfigDialog::GeneralSettingsChanged)
+
+ // Recording
+ EVT_CHOICE(IDC_RECORD + 1, ConfigDialog::GeneralSettingsChanged)
+ EVT_CHOICE(IDC_RECORD + 2, ConfigDialog::GeneralSettingsChanged)
+ EVT_CHOICE(IDC_RECORD + 3, ConfigDialog::GeneralSettingsChanged)
+ EVT_CHOICE(IDC_RECORD + 4, ConfigDialog::GeneralSettingsChanged)
+ EVT_CHOICE(IDC_RECORD + 5, ConfigDialog::GeneralSettingsChanged)
+ EVT_CHOICE(IDC_RECORD + 6, ConfigDialog::GeneralSettingsChanged)
+ EVT_CHOICE(IDC_RECORD + 7, ConfigDialog::GeneralSettingsChanged)
+ EVT_CHOICE(IDC_RECORD + 8, ConfigDialog::GeneralSettingsChanged)
+ EVT_CHOICE(IDC_RECORD + 9, ConfigDialog::GeneralSettingsChanged)
+ EVT_CHOICE(IDC_RECORD + 10, ConfigDialog::GeneralSettingsChanged)
+ EVT_CHOICE(IDC_RECORD + 11, ConfigDialog::GeneralSettingsChanged)
+ EVT_CHOICE(IDC_RECORD + 12, ConfigDialog::GeneralSettingsChanged)
+ EVT_CHOICE(IDC_RECORD + 13, ConfigDialog::GeneralSettingsChanged)
+ EVT_CHOICE(IDC_RECORD + 14, ConfigDialog::GeneralSettingsChanged)
+ EVT_CHOICE(IDC_RECORD + 15, ConfigDialog::GeneralSettingsChanged)
+
+ EVT_BUTTON(IDB_RECORD + 1, ConfigDialog::RecordMovement)
+ EVT_BUTTON(IDB_RECORD + 2, ConfigDialog::RecordMovement)
+ EVT_BUTTON(IDB_RECORD + 3, ConfigDialog::RecordMovement)
+ EVT_BUTTON(IDB_RECORD + 4, ConfigDialog::RecordMovement)
+ EVT_BUTTON(IDB_RECORD + 5, ConfigDialog::RecordMovement)
+ EVT_BUTTON(IDB_RECORD + 6, ConfigDialog::RecordMovement)
+ EVT_BUTTON(IDB_RECORD + 7, ConfigDialog::RecordMovement)
+ EVT_BUTTON(IDB_RECORD + 8, ConfigDialog::RecordMovement)
+ EVT_BUTTON(IDB_RECORD + 9, ConfigDialog::RecordMovement)
+ EVT_BUTTON(IDB_RECORD + 10, ConfigDialog::RecordMovement)
+ EVT_BUTTON(IDB_RECORD + 11, ConfigDialog::RecordMovement)
+ EVT_BUTTON(IDB_RECORD + 12, ConfigDialog::RecordMovement)
+ EVT_BUTTON(IDB_RECORD + 13, ConfigDialog::RecordMovement)
+ EVT_BUTTON(IDB_RECORD + 14, ConfigDialog::RecordMovement)
+ EVT_BUTTON(IDB_RECORD + 15, ConfigDialog::RecordMovement)
+
+ // Gamepad
+ EVT_COMBOBOX(IDC_JOYNAME, ConfigDialog::GeneralSettingsChanged)
+ EVT_COMBOBOX(ID_TRIGGER_TYPE, ConfigDialog::GeneralSettingsChanged)
+ EVT_COMBOBOX(ID_TILT_INPUT, ConfigDialog::GeneralSettingsChanged)
+ EVT_COMBOBOX(ID_TILT_RANGE_ROLL, ConfigDialog::GeneralSettingsChanged)
+ EVT_COMBOBOX(ID_TILT_RANGE_PITCH, ConfigDialog::GeneralSettingsChanged)
+ EVT_COMBOBOX(IDCB_LEFT_DIAGONAL, ConfigDialog::GeneralSettingsChanged)
+ EVT_COMBOBOX(IDCB_DEAD_ZONE_LEFT, ConfigDialog::GeneralSettingsChanged)
+ EVT_COMBOBOX(IDCB_DEAD_ZONE_RIGHT, ConfigDialog::GeneralSettingsChanged)
+ EVT_CHECKBOX(IDC_LEFT_C2S, ConfigDialog::GeneralSettingsChanged)
+ EVT_CHECKBOX(ID_TILT_INVERT_ROLL, ConfigDialog::GeneralSettingsChanged)
+ EVT_CHECKBOX(ID_TILT_INVERT_PITCH, ConfigDialog::GeneralSettingsChanged)
+ EVT_COMBOBOX(IDCB_NUNCHUCK_STICK, ConfigDialog::GeneralSettingsChanged)
+ EVT_COMBOBOX(IDCB_CC_LEFT_STICK, ConfigDialog::GeneralSettingsChanged)
+ EVT_COMBOBOX(IDCB_CC_RIGHT_STICK, ConfigDialog::GeneralSettingsChanged)
+ EVT_COMBOBOX(IDCB_CC_TRIGGERS, ConfigDialog::GeneralSettingsChanged)
+
+ // Wiimote
+ EVT_BUTTON(IDB_WM_A, ConfigDialog::OnButtonClick) EVT_BUTTON(IDB_WM_B, ConfigDialog::OnButtonClick)
+ EVT_BUTTON(IDB_WM_1, ConfigDialog::OnButtonClick) EVT_BUTTON(IDB_WM_2, ConfigDialog::OnButtonClick)
+ EVT_BUTTON(IDB_WM_P, ConfigDialog::OnButtonClick) EVT_BUTTON(IDB_WM_M, ConfigDialog::OnButtonClick) EVT_BUTTON(IDB_WM_H, ConfigDialog::OnButtonClick)
+ EVT_BUTTON(IDB_WM_L, ConfigDialog::OnButtonClick) EVT_BUTTON(IDB_WM_R, ConfigDialog::OnButtonClick)
+ EVT_BUTTON(IDB_WM_U, ConfigDialog::OnButtonClick) EVT_BUTTON(IDB_WM_D, ConfigDialog::OnButtonClick)
+ EVT_BUTTON(IDB_WM_SHAKE, ConfigDialog::OnButtonClick)
+ EVT_BUTTON(IDB_WM_PITCH_L, ConfigDialog::OnButtonClick) EVT_BUTTON(IDB_WM_PITCH_R, ConfigDialog::OnButtonClick)
+ // IR cursor
+ EVT_COMMAND_SCROLL(IDS_WIDTH, ConfigDialog::GeneralSettingsChangedScroll)
+ EVT_COMMAND_SCROLL(IDS_HEIGHT, ConfigDialog::GeneralSettingsChangedScroll)
+ EVT_COMMAND_SCROLL(IDS_LEFT, ConfigDialog::GeneralSettingsChangedScroll)
+ EVT_COMMAND_SCROLL(IDS_TOP, ConfigDialog::GeneralSettingsChangedScroll)
+
+ // Nunchuck
+ EVT_BUTTON(IDB_NC_Z, ConfigDialog::OnButtonClick) EVT_BUTTON(IDB_NC_C, ConfigDialog::OnButtonClick)
+ EVT_BUTTON(IDB_NC_L, ConfigDialog::OnButtonClick) EVT_BUTTON(IDB_NC_R, ConfigDialog::OnButtonClick)
+ EVT_BUTTON(IDB_NC_U, ConfigDialog::OnButtonClick) EVT_BUTTON(IDB_NC_D, ConfigDialog::OnButtonClick)
+ EVT_BUTTON(IDB_NC_SHAKE, ConfigDialog::OnButtonClick)
+
+ // Classic Controller
+ EVT_BUTTON(IDB_CC_A, ConfigDialog::OnButtonClick) EVT_BUTTON(IDB_CC_B, ConfigDialog::OnButtonClick) EVT_BUTTON(IDB_CC_X, ConfigDialog::OnButtonClick) EVT_BUTTON(IDB_CC_Y, ConfigDialog::OnButtonClick)
+ EVT_BUTTON(IDB_CC_P, ConfigDialog::OnButtonClick) EVT_BUTTON(IDB_CC_M, ConfigDialog::OnButtonClick) EVT_BUTTON(IDB_CC_H, ConfigDialog::OnButtonClick)
+ EVT_BUTTON(IDB_CC_TL, ConfigDialog::OnButtonClick) EVT_BUTTON(IDB_CC_ZL, ConfigDialog::OnButtonClick) EVT_BUTTON(IDB_CC_ZR, ConfigDialog::OnButtonClick) EVT_BUTTON(IDB_CC_TR, ConfigDialog::OnButtonClick)
+ EVT_BUTTON(IDB_CC_DL, ConfigDialog::OnButtonClick) EVT_BUTTON(IDB_CC_DU, ConfigDialog::OnButtonClick) EVT_BUTTON(IDB_CC_DR, ConfigDialog::OnButtonClick) EVT_BUTTON(IDB_CC_DD, ConfigDialog::OnButtonClick)
+ EVT_BUTTON(IDB_CC_DL, ConfigDialog::OnButtonClick) EVT_BUTTON(IDB_CC_DU, ConfigDialog::OnButtonClick) EVT_BUTTON(IDB_CC_DR, ConfigDialog::OnButtonClick) EVT_BUTTON(IDB_CC_DD, ConfigDialog::OnButtonClick)
+ EVT_BUTTON(IDB_CC_LL, ConfigDialog::OnButtonClick) EVT_BUTTON(IDB_CC_LU, ConfigDialog::OnButtonClick) EVT_BUTTON(IDB_CC_LR, ConfigDialog::OnButtonClick) EVT_BUTTON(IDB_CC_LD, ConfigDialog::OnButtonClick)
+ EVT_BUTTON(IDB_CC_RL, ConfigDialog::OnButtonClick) EVT_BUTTON(IDB_CC_RU, ConfigDialog::OnButtonClick) EVT_BUTTON(IDB_CC_RR, ConfigDialog::OnButtonClick) EVT_BUTTON(IDB_CC_RD, ConfigDialog::OnButtonClick)
+
+ EVT_BUTTON(IDB_ANALOG_LEFT_X, ConfigDialog::GetButtons)
+ EVT_BUTTON(IDB_ANALOG_LEFT_Y, ConfigDialog::GetButtons)
+ EVT_BUTTON(IDB_ANALOG_RIGHT_X, ConfigDialog::GetButtons)
+ EVT_BUTTON(IDB_ANALOG_RIGHT_Y, ConfigDialog::GetButtons)
+ EVT_BUTTON(IDB_TRIGGER_L, ConfigDialog::GetButtons)
+ EVT_BUTTON(IDB_TRIGGER_R, ConfigDialog::GetButtons)
+
+ EVT_TIMER(IDTM_UPDATE, ConfigDialog::Update)
+ EVT_TIMER(IDTM_UPDATE_ONCE, ConfigDialog::UpdateOnce)
+ EVT_TIMER(IDTM_SHUTDOWN, ConfigDialog::ShutDown)
+ EVT_TIMER(IDTM_BUTTON, ConfigDialog::OnButtonTimer)
+ EVT_TIMER(IDTM_UPDATE_PAD, ConfigDialog::UpdatePad)
+END_EVENT_TABLE()
+//////////////////////////////////////
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Class
+// ŻŻŻŻŻŻŻŻŻŻŻŻŻ
+ConfigDialog::ConfigDialog(wxWindow *parent, wxWindowID id, const wxString &title,
+ const wxPoint &position, const wxSize& size, long style)
+: wxDialog(parent, id, title, position, size, style)
+{
+ #if wxUSE_TIMER
+ m_TimeoutTimer = new wxTimer(this, IDTM_UPDATE);
+ m_ShutDownTimer = new wxTimer(this, IDTM_SHUTDOWN);
+ m_TimeoutOnce = new wxTimer(this, IDTM_UPDATE_ONCE);
+ m_ButtonMappingTimer = new wxTimer(this, IDTM_BUTTON);
+ m_UpdatePad = new wxTimer(this, IDTM_UPDATE_PAD);
+
+ // Reset values
+ m_bWaitForRecording = false;
+ m_bRecording = false;
+ GetButtonWaitingID = 0; GetButtonWaitingTimer = 0;
+
+ // Start the permanent timer
+ const int TimesPerSecond = 30;
+ m_UpdatePad->Start( floor((double)(1000 / TimesPerSecond)) );
+ #endif
+
+ ControlsCreated = false;
+ m_bEnableUseRealWiimote = true;
+ Page = 0;
+ m_vRecording.resize(RECORDING_ROWS + 1);
+ ClickedButton = NULL;
+
+ g_Config.Load();
+ CreateGUIControls();
+ LoadFile();
+ // Set control values
+ UpdateGUI();
+
+ wxTheApp->Connect(wxID_ANY, wxEVT_KEY_DOWN, // Keyboard
+ wxKeyEventHandler(ConfigDialog::OnKeyDown),
+ (wxObject*)0, this);
+}
+
+ConfigDialog::~ConfigDialog()
+{
+}
+
+void ConfigDialog::OnKeyDown(wxKeyEvent& event)
+{
+ event.Skip();
+
+ // Save the key
+ g_Pressed = event.GetKeyCode();
+
+ // Escape a recording event
+ if (event.GetKeyCode() == WXK_ESCAPE)
+ {
+ m_bWaitForRecording = false;
+ m_bRecording = false;
+ UpdateGUI();
+ }
+
+ // ----------------------------------------------------
+ // Handle the keyboard key mapping
+ // ------------------
+ std::string StrKey;
+ if(ClickedButton != NULL)
+ {
+ // Allow the escape key to set a blank key
+ if (g_Pressed == WXK_ESCAPE)
+ {
+ SaveKeyboardMapping(Page, ClickedButton->GetId(), -1);
+ SetButtonText(ClickedButton->GetId(), "");
+ ClickedButton = NULL;
+ return;
+ }
+
+ #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
+ char KeyStr[64] = {0}; strcpy(KeyStr, InputCommon::VKToString(i).c_str());
+ SetButtonText(ClickedButton->GetId(), KeyStr);
+ // Save the setting
+ SaveKeyboardMapping(Page, ClickedButton->GetId(), i);
+ }
+ }
+ #elif defined(HAVE_X11) && HAVE_X11
+ //pad[page].keyForControl[ClickedButton->GetId()] = wxCharCodeWXToX(event.GetKeyCode());
+ //ClickedButton->SetLabel(wxString::Format(_T("%c"), event.GetKeyCode()));
+ #endif
+ }
+
+ // Remove the button control pointer
+ ClickedButton = NULL;
+ // ---------------------------
+}
+
+// Input button clicked
+void ConfigDialog::OnButtonClick(wxCommandEvent& event)
+{
+ //INFO_LOG(CONSOLE, "OnButtonClick: %i\n", g_Pressed);
+
+ // 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; }
+
+ // Reset the old label
+ if(ClickedButton) ClickedButton->SetLabel(OldLabel);
+
+ // Create the button object
+ ClickedButton = (wxButton *)event.GetEventObject();
+ OldLabel = ClickedButton->GetLabel();
+ ClickedButton->SetLabel(wxT(""));
+ // Allow Tab and directional keys to
+ ClickedButton->SetWindowStyle(wxWANTS_CHARS);
+}
+
+
+void ConfigDialog::OnClose(wxCloseEvent& event)
+{
+ g_FrameOpen = false;
+ m_UpdatePad->Stop();
+ SaveFile();
+ g_Config.Save();
+ //SuccessAlert("Saved\n");
+ if (!g_EmulatorRunning) Shutdown();
+ // This will let the Close() function close and remove the wxDialog
+ event.Skip();
+}
+
+/* Timeout the shutdown. In Windows at least the g_pReadThread execution will hang at any attempt to
+ call a frame function after the main thread has entered WaitForSingleObject() or any other loop.
+ We must therefore shut down the thread from here and wait for that before we can call ShutDown(). */
+void ConfigDialog::ShutDown(wxTimerEvent& WXUNUSED(event))
+{
+ // Close() is a wxWidgets function that will trigger EVT_CLOSE() and then call this->Destroy().
+ if(!WiiMoteReal::g_ThreadGoing)
+ {
+ m_ShutDownTimer->Stop();
+ Close();
+ }
+}
+
+void ConfigDialog::CloseClick(wxCommandEvent& event)
+{
+ switch(event.GetId())
+ {
+ case ID_CLOSE:
+ // Wait for the Wiimote thread to stop, then close and shutdown
+ if(!g_EmulatorRunning)
+ {
+ WiiMoteReal::g_Shutdown = true;
+ m_ShutDownTimer->Start(10);
+ }
+ // Close directly
+ else
+ {
+ Close();
+ }
+ break;
+ case ID_APPLY:
+ SaveButtonMappingAll(Page);
+ g_Config.Save();
+ SaveFile();
+ WiiMoteEmu::LoadRecordedMovements();
+ break;
+ }
+}
+
+void ConfigDialog::AboutClick(wxCommandEvent& WXUNUSED (event))
+{
+}
+
+// Execute a delayed function
+void ConfigDialog::UpdateOnce(wxTimerEvent& event)
+{
+ switch(event.GetId())
+ {
+ case IDTM_UPDATE_ONCE:
+ // Reenable the checkbox
+ m_bEnableUseRealWiimote = true;
+ SetCursor(wxCursor(wxCURSOR_ARROW));
+ UpdateGUI();
+ break;
+ }
+}
+//////////////////////////////////////
+
+
+
+////////////////////////////////////////////////////////////////////////////
+// Save Settings
+/* ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
+
+ Saving is currently done when:
+
+ 1. Closing the configuration window
+ 2. Changing the gamepad
+ 3. When the gamepad is enabled or disbled
+
+ Input: ChangePad needs to be used when we change the pad for a slot. Slot needs to be used when
+ we only want to save changes to one slot.
+*/
+void ConfigDialog::DoSave(bool ChangePad, int Slot)
+{
+ // Replace "" with "-1" before we are saving
+ ToBlank(false);
+
+ if(ChangePad)
+ {
+ // Since we are selecting the pad to save to by the Id we can't update it when we change the pad
+ for(int i = 0; i < 4; i++) SaveButtonMapping(i, true);
+ // Save the settings for the current pad
+ g_Config.Save(Slot);
+ // Now we can update the ID
+ WiiMoteEmu::PadMapping[Page].ID = m_Joyname[Page]->GetSelection();
+ }
+ else
+ {
+ // Update PadMapping[] from the GUI controls
+ for(int i = 0; i < 4; i++) SaveButtonMapping(i);
+ g_Config.Save(Slot);
+ }
+
+ // Then change it back to ""
+ ToBlank();
+
+ INFO_LOG(CONSOLE, "WiiMoteEmu::PadMapping[%i].ID = %i\n", Page, m_Joyname[Page]->GetSelection());
+}
+//////////////////////////////////////
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Bitmap box and dot
+// ----------------
+wxBitmap ConfigDialog::CreateBitmap()
+{
+ BoxW = 70, BoxH = 70;
+ wxBitmap bitmap(BoxW, BoxH);
+ wxMemoryDC dc;
+ dc.SelectObject(bitmap);
+
+ // Set outline and fill colors
+ //wxBrush LightBlueBrush(_T("#0383f0"));
+ //wxPen LightBluePen(_T("#80c5fd"));
+ //wxPen LightGrayPen(_T("#909090"));
+ 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 ConfigDialog::CreateBitmapDot()
+{
+ int w = 2, h = 2;
+ wxBitmap bitmap(w, h);
+ wxMemoryDC dc;
+ dc.SelectObject(bitmap);
+
+ // Set outline and fill colors
+ //wxBrush RedBrush(_T("#0383f0"));
+ //wxPen RedPen(_T("#80c5fd"));
+ dc.SetPen(*wxRED_PEN);
+ dc.SetBrush(*wxRED_BRUSH);
+
+ dc.Clear();
+ dc.DrawRectangle(0, 0, w, h);
+ dc.SelectObject(wxNullBitmap);
+ return bitmap;
+}
+wxBitmap ConfigDialog::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 ConfigDialog::CreateBitmapClear()
+{
+ wxBitmap bitmap(BoxW, BoxH);
+ wxMemoryDC dc;
+ dc.SelectObject(bitmap);
+
+ // Set outline and fill colors
+ //dc.SetBrush(*wxTRANSPARENT_BRUSH);
+
+ dc.Clear();
+ //dc.DrawRectangle(0, 0, BoxW, BoxH);
+ //dc.SelectObject(wxNullBitmap);
+ return bitmap;
+}
+//////////////////////////////////////
+
+
+void ConfigDialog::CreateGUIControls()
+{
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Notebook
+ // ----------------
+ m_Notebook = new wxNotebook(this, ID_NOTEBOOK, wxDefaultPosition, wxDefaultSize);
+
+ for (int i = 0; i < MAX_WIIMOTES; i++)
+ {
+ // Controller pages
+ m_Controller[i] = new wxPanel(m_Notebook, ID_CONTROLLERPAGE1 + i, wxDefaultPosition, wxDefaultSize);
+ m_Notebook->AddPage(m_Controller[i], wxString::Format(wxT("Wiimote %d"), i+1));
+ }
+
+ m_PageRecording = new wxPanel(m_Notebook, ID_PAGE_RECORDING, wxDefaultPosition, wxDefaultSize);
+ m_Notebook->AddPage(m_PageRecording, wxT("Recording"));
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Text lists
+ // ----------------
+
+ // Search for devices and add them to the device list
+ wxArrayString StrJoyname; // The string array
+ if (WiiMoteEmu::NumGoodPads > 0)
+ {
+ for (int x = 0; x < (int)WiiMoteEmu::joyinfo.size(); x++)
+ StrJoyname.Add(wxString::FromAscii(WiiMoteEmu::joyinfo[x].Name.c_str()));
+ }
+ else
+ {
+ StrJoyname.Add(wxString::FromAscii(""));
+ }
+
+ // The tilt list
+ wxArrayString StrTilt;
+ StrTilt.Add(wxString::FromAscii(""));
+ StrTilt.Add(wxString::FromAscii("Keyboard"));
+ StrTilt.Add(wxString::FromAscii("Analog 1"));
+ StrTilt.Add(wxString::FromAscii("Analog 2"));
+ StrTilt.Add(wxString::FromAscii("Triggers"));
+ // The range is in degrees and are set at even 5 degrees values
+ wxArrayString StrTiltRangeRoll, StrTiltRangePitch;
+ for (int i = 0; i < 37; i++)
+ StrTiltRangeRoll.Add(wxString::Format(wxT("%i"), i*5));
+ for (int i = 0; i < 37; i++)
+ StrTiltRangePitch.Add(wxString::Format(wxT("%i"), i*5));
+
+ // The Trigger type list
+ wxArrayString StrTriggerType;
+ StrTriggerType.Add(wxString::FromAscii("SDL")); // -0x8000 to 0x7fff
+ StrTriggerType.Add(wxString::FromAscii("XInput")); // 0x00 to 0xff
+
+ // The Nunchuck stick list
+ wxArrayString StrNunchuck;
+ StrNunchuck.Add(wxString::FromAscii("Keyboard"));
+ StrNunchuck.Add(wxString::FromAscii("Analog 1"));
+ StrNunchuck.Add(wxString::FromAscii("Analog 2"));
+
+ // The Classic Controller triggers list
+ wxArrayString StrCcTriggers;
+ StrCcTriggers.Add(wxString::FromAscii("Keyboard"));
+ StrCcTriggers.Add(wxString::FromAscii("Triggers"));
+
+ // A small type font
+ wxFont m_SmallFont(7, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
+ ///////////////////////////////////////
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // This can take a few seconds so we show a progress bar for it
+ // ----------------
+ wxProgressDialog dialog(_T("Opening Wii Remote Configuration"),
+ wxT("Loading controls..."),
+ 6, // range
+ this, // parent
+ wxPD_APP_MODAL |
+ // wxPD_AUTO_HIDE | -- try this as well
+ wxPD_ELAPSED_TIME |
+ wxPD_ESTIMATED_TIME |
+ wxPD_REMAINING_TIME |
+ wxPD_SMOOTH // - makes indeterminate mode bar on WinXP very small
+ );
+ // I'm not sure what parent this refers to
+ dialog.CenterOnParent();
+ ///////////////////////////////////////
+
+ /* Populate all four pages. Page 2, 3 and 4 are currently disabled since we can't use more than one
+ Wiimote at the moment */
+ for (int i = 0; i < MAX_WIIMOTES; i++)
+ {
+
+ ////////////////////////////////////////////////////
+ // General and basic Settings
+ // ----------------
+
+ // Configuration controls sizes
+ static const int TxtW = 50, TxtH = 19, ChW = 257, BtW = 75, BtH = 20;
+
+ // Basic Settings
+ m_WiimoteOnline[i] = new wxCheckBox(m_Controller[i], IDC_WIMOTE_ON, wxT("Wiimote On"), wxDefaultPosition, wxSize(ChW, -1));
+ // Emulated Wiimote
+ m_SidewaysDPad[i] = new wxCheckBox(m_Controller[i], ID_SIDEWAYSDPAD, wxT("Sideways D-Pad"), wxDefaultPosition, wxSize(ChW, -1));
+ // Extension
+ m_WiiMotionPlusConnected[i] = new wxCheckBox(m_Controller[i], wxID_ANY, wxT("Wii Motion Plus Connected"), wxDefaultPosition, wxSize(ChW, -1), 0, wxDefaultValidator);
+ m_NunchuckConnected[i] = new wxCheckBox(m_Controller[i], ID_NUNCHUCKCONNECTED, wxT("Nunchuck Connected"));
+ m_ClassicControllerConnected[i] = new wxCheckBox(m_Controller[i], ID_CLASSICCONTROLLERCONNECTED, wxT("Classic Controller Connected"));
+ m_BalanceBoardConnected[i] = new wxCheckBox(m_Controller[i], wxID_ANY, wxT("Balance Board Connected"));
+ m_GuitarHeroGuitarConnected[i] = new wxCheckBox(m_Controller[i], wxID_ANY, wxT("Guitar Hero Guitar Connected"));
+ m_GuitarHeroWorldTourDrumsConnected[i] = new wxCheckBox(m_Controller[i], wxID_ANY, wxT("Guitar Hero World Tour Drums Connected"));
+ // Real Wiimote
+ m_ConnectRealWiimote[i] = new wxCheckBox(m_Controller[i], ID_CONNECT_REAL, wxT("Connect Real Wiimote"), wxDefaultPosition, wxSize(ChW, -1));
+ m_UseRealWiimote[i] = new wxCheckBox(m_Controller[i], ID_USE_REAL, wxT("Use Real Wiimote"));
+
+ // Default values
+ m_WiimoteOnline[0]->SetValue(true);
+ m_NunchuckConnected[0]->SetValue(g_Config.bNunchuckConnected);
+ m_ClassicControllerConnected[0]->SetValue(g_Config.bClassicControllerConnected);
+ m_SidewaysDPad[0]->SetValue(g_Config.bSidewaysDPad);
+ m_ConnectRealWiimote[0]->SetValue(g_Config.bConnectRealWiimote);
+ m_UseRealWiimote[0]->SetValue(g_Config.bUseRealWiimote);
+
+ m_WiimoteOnline[0]->Enable(false);
+ m_WiiMotionPlusConnected[0]->Enable(false);
+ m_BalanceBoardConnected[0]->Enable(false);
+ m_GuitarHeroGuitarConnected[0]->Enable(false);
+ m_GuitarHeroWorldTourDrumsConnected[0]->Enable(false);
+
+ // Tooltips
+ m_WiimoteOnline[i]->SetToolTip(wxString::Format(wxT("Decide if Wiimote %i shall be detected by the game"), i));
+ m_ConnectRealWiimote[i]->SetToolTip(wxT("Connected to the real wiimote. This can not be changed during gameplay."));
+ m_UseRealWiimote[i]->SetToolTip(wxT(
+ "Use the real Wiimote in the game. This can be changed during gameplay. This can not be selected"
+ " when a recording is to be done. No status in this window will be updated when this is checked."));
+
+ // -----------------------------------------------
+ // Screen size
+ // ---------------------
+ // Controls
+ m_TextScreenWidth[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Width: 000"));
+ m_TextScreenHeight[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Height: 000"));
+ m_TextScreenLeft[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Left: 000"));
+ m_TextScreenTop[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Top: 000"));
+ m_TextAR[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Aspect Ratio"));
+
+ m_SliderWidth[i] = new wxSlider(m_Controller[i], IDS_WIDTH, 0, 100, 923, wxDefaultPosition, wxSize(75, -1));
+ m_SliderHeight[i] = new wxSlider(m_Controller[i], IDS_HEIGHT, 0, 0, 727, wxDefaultPosition, wxSize(75, -1));
+ m_SliderLeft[i] = new wxSlider(m_Controller[i], IDS_LEFT, 0, 100, 500, wxDefaultPosition, wxSize(75, -1));
+ m_SliderTop[i] = new wxSlider(m_Controller[i], IDS_TOP, 0, 0, 500, wxDefaultPosition, wxSize(75, -1));
+ //m_ScreenSize = new wxCheckBox(m_Controller[i], IDC_SCREEN_SIZE, wxT("Adjust screen size and position"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator);
+
+ m_CheckAR43[i] = new wxCheckBox(m_Controller[i], wxID_ANY, wxT("4:3"), wxDefaultPosition, wxSize(-1, -1), 0, wxDefaultValidator);
+ m_CheckAR169[i] = new wxCheckBox(m_Controller[i], wxID_ANY, wxT("16:9"), wxDefaultPosition, wxSize(-1, -1), 0, wxDefaultValidator);
+ m_Crop[i] = new wxCheckBox(m_Controller[i], wxID_ANY, wxT("Crop"), wxDefaultPosition, wxSize(-1, -1), 0, wxDefaultValidator);
+
+ // Sizers
+ m_SizerIRPointerWidth[i] = new wxBoxSizer(wxHORIZONTAL);
+ m_SizerIRPointerWidth[i]->Add(m_TextScreenLeft[i], 0, wxEXPAND | (wxTOP), 3);
+ m_SizerIRPointerWidth[i]->Add(m_SliderLeft[i], 0, wxEXPAND | (wxRIGHT), 0);
+ m_SizerIRPointerWidth[i]->Add(m_TextScreenWidth[i], 0, wxEXPAND | (wxTOP), 3);
+ m_SizerIRPointerWidth[i]->Add(m_SliderWidth[i], 0, wxEXPAND | (wxLEFT), 0);
+
+ m_SizerIRPointerHeight[i] = new wxBoxSizer(wxHORIZONTAL);
+ m_SizerIRPointerHeight[i]->Add(m_TextScreenTop[i], 0, wxEXPAND | (wxTOP), 3);
+ m_SizerIRPointerHeight[i]->Add(m_SliderTop[i], 0, wxEXPAND | (wxRIGHT), 0);
+ m_SizerIRPointerHeight[i]->Add(m_TextScreenHeight[i], 0, wxEXPAND | (wxTOP), 3);
+ m_SizerIRPointerHeight[i]->Add(m_SliderHeight[i], 0, wxEXPAND | (wxLEFT), 0);
+
+ m_SizerIRPointerScreen[i] = new wxBoxSizer(wxHORIZONTAL);
+ m_SizerIRPointerScreen[i]->Add(m_TextAR[i], 0, wxEXPAND | (wxTOP), 0);
+ m_SizerIRPointerScreen[i]->Add(m_CheckAR43[i], 0, wxEXPAND | (wxLEFT), 5);
+ m_SizerIRPointerScreen[i]->Add(m_CheckAR169[i], 0, wxEXPAND | (wxLEFT), 5);
+ m_SizerIRPointerScreen[i]->Add(m_Crop[i], 0, wxEXPAND | (wxLEFT), 5);
+
+ m_SizerIRPointer[i] = new wxStaticBoxSizer(wxVERTICAL, m_Controller[i], wxT("IR pointer"));
+ //m_SizerIRPointer[i]->Add(m_ScreenSize[i], 0, wxEXPAND | (wxALL), 5);
+ m_SizerIRPointer[i]->Add(m_SizerIRPointerWidth[i], 0, wxEXPAND | (wxLEFT | wxDOWN | wxRIGHT), 5);
+ m_SizerIRPointer[i]->Add(m_SizerIRPointerHeight[i], 0, wxEXPAND | (wxLEFT | wxDOWN | wxRIGHT), 5);
+ m_SizerIRPointer[i]->Add(m_SizerIRPointerScreen[i], 0, wxEXPAND | (wxLEFT | wxDOWN | wxRIGHT), 5);
+
+ // Default values
+ m_CheckAR43[i]->SetValue(g_Config.bKeepAR43);
+ m_CheckAR169[i]->SetValue(g_Config.bKeepAR169);
+ m_Crop[i]->SetValue(g_Config.bCrop);
+
+ // These are changed from the graphics plugin settings, so they are just here to show the loaded status
+ m_TextAR[i]->Enable(false);
+ m_CheckAR43[i]->Enable(false);
+ m_CheckAR169[i]->Enable(false);
+ m_Crop[i]->Enable(false);
+
+ // Tool tips
+ //m_ScreenSize[i]->SetToolTip(wxT("Use the adjusted screen size."));
+ // -------------------------------
+
+ // --------------------------------------------------------------------
+ // Row 1 Sizers: General settings
+ // -----------------------------
+ m_SizeBasic[i] = new wxStaticBoxSizer(wxVERTICAL, m_Controller[i], wxT("General Settings"));
+ m_SizeEmu[i] = new wxStaticBoxSizer(wxVERTICAL, m_Controller[i], wxT("Emulated Wiimote"));
+ m_SizeExtensions[i] = new wxStaticBoxSizer(wxVERTICAL, m_Controller[i], wxT("Emulated Extension"));
+ m_SizeReal[i] = new wxStaticBoxSizer(wxVERTICAL, m_Controller[i], wxT("Real Wiimote"));
+
+ m_SizeBasicPadding[i] = new wxBoxSizer(wxVERTICAL); m_SizeBasic[i]->Add(m_SizeBasicPadding[i], 0, wxEXPAND | (wxALL), 5);
+ m_SizeBasicPadding[i]->Add(m_WiimoteOnline[i], 0, wxEXPAND | (wxUP), 2);
+
+ m_SizeEmuPadding[i] = new wxBoxSizer(wxVERTICAL); m_SizeEmu[i]->Add(m_SizeEmuPadding[i], 0, wxEXPAND | (wxALL), 5);
+ m_SizeEmuPadding[i]->Add(m_SidewaysDPad[i], 0, wxEXPAND | (wxUP), 0);
+
+ m_SizeRealPadding[i] = new wxBoxSizer(wxVERTICAL); m_SizeReal[i]->Add(m_SizeRealPadding[i], 0, wxEXPAND | (wxALL), 5);
+ m_SizeRealPadding[i]->Add(m_ConnectRealWiimote[i], 0, wxEXPAND | (wxUP), 0);
+ m_SizeRealPadding[i]->Add(m_UseRealWiimote[i], 0, wxEXPAND | (wxUP), 2);
+
+ m_SizeExtensionsPadding[i] = new wxBoxSizer(wxVERTICAL); m_SizeExtensions[i]->Add(m_SizeExtensionsPadding[i], 0, wxEXPAND | (wxALL), 5);
+ m_SizeExtensionsPadding[i]->Add(m_WiiMotionPlusConnected[i], 0, (wxUP), 0);
+ m_SizeExtensionsPadding[i]->Add(m_NunchuckConnected[i], 0, (wxUP), 2);
+ m_SizeExtensionsPadding[i]->Add(m_ClassicControllerConnected[i], 0, (wxUP), 2);
+ m_SizeExtensionsPadding[i]->Add(m_BalanceBoardConnected[i], 0, (wxUP), 2);
+ m_SizeExtensionsPadding[i]->Add(m_GuitarHeroGuitarConnected[i], 0, (wxUP), 2);
+ m_SizeExtensionsPadding[i]->Add(m_GuitarHeroWorldTourDrumsConnected[i], 0, (wxUP), 2);
+
+ m_SizeBasicGeneral[i] = new wxBoxSizer(wxHORIZONTAL);
+ m_SizeBasicGeneralLeft[i] = new wxBoxSizer(wxVERTICAL);
+ m_SizeBasicGeneralRight[i] = new wxBoxSizer(wxVERTICAL);
+
+ m_SizeBasicGeneralLeft[i]->Add(m_SizeReal[i], 0, wxEXPAND | (wxUP), 0);
+ m_SizeBasicGeneralLeft[i]->Add(m_SizeExtensions[i], 0, wxEXPAND | (wxUP), 5);
+
+ m_SizeBasicGeneralRight[i]->Add(m_SizeBasic[i], 0, wxEXPAND | (wxUP), 0);
+ m_SizeBasicGeneralRight[i]->Add(m_SizeEmu[i], 0, wxEXPAND | (wxUP), 5);
+ m_SizeBasicGeneralRight[i]->Add(m_SizerIRPointer[i], 0, wxEXPAND | (wxUP), 5);
+
+ m_SizeBasicGeneral[i]->Add(m_SizeBasicGeneralLeft[i], 0, wxEXPAND | (wxUP), 0);
+ m_SizeBasicGeneral[i]->Add(m_SizeBasicGeneralRight[i], 0, wxEXPAND | (wxLEFT), 5);
+ // ------------------------
+
+ ///////////////////////////
+
+
+
+
+ ////////////////////////////////////////////////////////////////////////
+ // Gamepad input
+ // ----------------
+
+ // --------------------------------------------------------------------
+ // Controller
+ // -----------------------------
+
+ // Controller
+ m_Joyname[i] = new wxComboBox(m_Controller[i], IDC_JOYNAME, StrJoyname[0], wxDefaultPosition, wxSize(200, -1), StrJoyname, wxCB_READONLY);
+
+ // Circle to square
+ m_CheckC2S[i] = new wxCheckBox(m_Controller[i], IDC_LEFT_C2S, wxT("Circle To Square"));
+
+ // The drop down menu for the circle to square adjustment
+ m_CheckC2SLabel[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Diagonal"));
+ wxArrayString asStatusInSet;
+ asStatusInSet.Add(wxT("100%"));
+ asStatusInSet.Add(wxT("95%"));
+ asStatusInSet.Add(wxT("90%"));
+ asStatusInSet.Add(wxT("85%"));
+ asStatusInSet.Add(wxT("80%"));
+ m_ComboDiagonal[i] = new wxComboBox(m_Controller[i], IDCB_LEFT_DIAGONAL, asStatusInSet[0], wxDefaultPosition, wxDefaultSize, asStatusInSet, wxCB_READONLY);
+
+ // Dead zone
+ m_ComboDeadZoneLabel[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Dead Zone"));
+ wxArrayString TextDeadZone;
+ for (int j = 0; j <= 50; j++) TextDeadZone.Add(wxString::Format(wxT("%i%%"), j));
+ m_ComboDeadZoneLeft[i] = new wxComboBox(m_Controller[i], IDCB_DEAD_ZONE_LEFT, TextDeadZone[0], wxDefaultPosition, wxDefaultSize, TextDeadZone, wxCB_READONLY);
+ m_ComboDeadZoneRight[i] = new wxComboBox(m_Controller[i], IDCB_DEAD_ZONE_RIGHT, TextDeadZone[0], wxDefaultPosition, wxDefaultSize, TextDeadZone, wxCB_READONLY);
+
+ // Tooltips
+ m_Joyname[i]->SetToolTip(wxT("Save your settings and configure another joypad"));
+ m_CheckC2S[i]->SetToolTip(wxT(
+ "This will convert a circular stick radius to a square stick radius."
+ " This can be useful for the pitch and roll emulation."
+ ));
+ m_CheckC2SLabel[i]->SetToolTip(wxT(
+ "To produce a perfect square circle in the 'Out' window you have to manually set"
+ "\nyour diagonal values here from what is shown in the 'In' window."
+ ));
+
+ // Sizers
+ m_gDeadZone[i] = new wxBoxSizer(wxVERTICAL);
+ m_gDeadZoneHoriz[i] = new wxBoxSizer(wxHORIZONTAL);
+ m_gDeadZoneHoriz[i]->Add(m_ComboDeadZoneLeft[i], 0, (wxUP), 0);
+ m_gDeadZoneHoriz[i]->Add(m_ComboDeadZoneRight[i], 0, (wxUP), 0);
+ m_gDeadZone[i]->Add(m_ComboDeadZoneLabel[i], 0, wxALIGN_CENTER | (wxUP), 0);
+ m_gDeadZone[i]->Add(m_gDeadZoneHoriz[i], 0, wxALIGN_CENTER | (wxUP), 2);
+
+ m_gCircle2Square[i] = new wxBoxSizer(wxHORIZONTAL);
+ m_gCircle2Square[i]->Add(m_CheckC2SLabel[i], 0, (wxUP), 4);
+ m_gCircle2Square[i]->Add(m_ComboDiagonal[i], 0, (wxLEFT), 2);
+
+ m_gCircle2SquareVert[i] = new wxBoxSizer(wxVERTICAL);
+ m_gCircle2SquareVert[i]->Add(m_CheckC2S[i], 0, wxALIGN_CENTER | (wxUP), 0);
+ m_gCircle2SquareVert[i]->Add(m_gCircle2Square[i], 0, wxALIGN_CENTER | (wxUP), 2);
+
+ m_gC2SDeadZone[i] = new wxBoxSizer(wxHORIZONTAL);
+ m_gC2SDeadZone[i]->Add(m_gDeadZone[i], 0, (wxUP), 0);
+ m_gC2SDeadZone[i]->Add(m_gCircle2SquareVert[i], 0, (wxLEFT), 8);
+
+ m_gJoyname[i] = new wxStaticBoxSizer (wxVERTICAL, m_Controller[i], wxT("Gamepad"));
+ m_gJoyname[i]->AddStretchSpacer();
+ m_gJoyname[i]->Add(m_Joyname[i], 0, wxALIGN_CENTER | (wxLEFT | wxRIGHT | wxDOWN), 5);
+ m_gJoyname[i]->Add(m_gC2SDeadZone[i], 0, wxALIGN_CENTER | (wxLEFT | wxRIGHT | wxDOWN), 5);
+ m_gJoyname[i]->AddStretchSpacer();
+
+
+ // --------------------------------------------------------------------
+ // Tilt Wiimote
+ // -----------------------------
+ /**/
+ // Controls
+ m_TiltComboInput[i] = new wxComboBox(m_Controller[i], ID_TILT_INPUT, StrTilt[0], wxDefaultPosition, wxDefaultSize, StrTilt, wxCB_READONLY);
+ m_TiltComboRangeRoll[i] = new wxComboBox(m_Controller[i], ID_TILT_RANGE_ROLL, StrTiltRangeRoll[0], wxDefaultPosition, wxDefaultSize, StrTiltRangeRoll, wxCB_READONLY);
+ m_TiltComboRangePitch[i] = new wxComboBox(m_Controller[i], ID_TILT_RANGE_PITCH, StrTiltRangePitch[0], wxDefaultPosition, wxDefaultSize, StrTiltRangePitch, wxCB_READONLY);
+ m_TiltTextRoll[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Roll"));
+ m_TiltTextPitch[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Pitch"));
+ m_TiltInvertRoll[i] = new wxCheckBox(m_Controller[i], ID_TILT_INVERT_ROLL, wxT("Invert"));
+ m_TiltInvertPitch[i] = new wxCheckBox(m_Controller[i], ID_TILT_INVERT_PITCH, wxT("Invert"));
+
+ // Sizers
+ m_TiltGrid[i] = new wxGridBagSizer(0, 0);
+ m_TiltGrid[i]->Add(m_TiltTextRoll[i], wxGBPosition(0, 0), wxGBSpan(1, 1), (wxTOP), 4);
+ m_TiltGrid[i]->Add(m_TiltComboRangeRoll[i], wxGBPosition(0, 1), wxGBSpan(1, 1), (wxLEFT), 2);
+ m_TiltGrid[i]->Add(m_TiltInvertRoll[i], wxGBPosition(0, 2), wxGBSpan(1, 1), (wxLEFT | wxTOP), 4);
+
+ m_TiltGrid[i]->Add(m_TiltTextPitch[i], wxGBPosition(1, 0), wxGBSpan(1, 1), (wxTOP), 6);
+ m_TiltGrid[i]->Add(m_TiltComboRangePitch[i], wxGBPosition(1, 1), wxGBSpan(1, 1), (wxLEFT | wxTOP | wxDOWN), 2);
+ m_TiltGrid[i]->Add(m_TiltInvertPitch[i], wxGBPosition(1, 2), wxGBSpan(1, 1), (wxLEFT | wxTOP), 4);
+
+ // For additional padding options if needed
+ //m_TiltHoriz[i] = new wxBoxSizer(wxHORIZONTAL);
+
+ m_gTilt[i] = new wxStaticBoxSizer (wxVERTICAL, m_Controller[i], wxT("Roll and pitch"));
+ m_gTilt[i]->AddStretchSpacer();
+ m_gTilt[i]->Add(m_TiltComboInput[i], 0, wxEXPAND | (wxLEFT | wxRIGHT | wxDOWN), 5);
+ m_gTilt[i]->Add(m_TiltGrid[i], 0, wxEXPAND | (wxLEFT | wxRIGHT), 5);
+ m_gTilt[i]->AddStretchSpacer();
+
+ //Set values
+ m_TiltComboInput[i]->SetSelection(g_Config.Trigger.Type);
+ m_TiltComboRangeRoll[i]->SetValue(wxString::Format(wxT("%i"), g_Config.Trigger.Range.Roll));
+ m_TiltComboRangePitch[i]->SetValue(wxString::Format(wxT("%i"), g_Config.Trigger.Range.Pitch));
+
+ // Tooltips
+ m_TiltComboInput[i]->SetToolTip(wxT("Control tilting by an analog gamepad stick, an analog trigger or the keyboard."));
+ m_TiltComboRangeRoll[i]->SetToolTip(wxT("The maximum roll in degrees. Set to 0 to turn off."));
+ m_TiltComboRangePitch[i]->SetToolTip(wxT("The maximum pitch in degrees. Set to 0 to turn off."));
+
+ // --------------------------------------------------------------------
+ // Analog triggers
+ // -----------------------------
+ /**/
+ m_gTrigger[i] = new wxStaticBoxSizer (wxHORIZONTAL, m_Controller[i], wxT("Triggers"));
+
+ m_TriggerStatusL[i]= new wxStaticText(m_Controller[i], wxID_ANY, wxT("Left: "));
+ m_TriggerStatusR[i]= new wxStaticText(m_Controller[i], wxID_ANY, wxT("Right: "));
+ m_TriggerStatusLx[i]= new wxStaticText(m_Controller[i], wxID_ANY, wxT("000"), wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT);
+ m_TriggerStatusRx[i]= new wxStaticText(m_Controller[i], wxID_ANY, wxT("000"), wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT);
+
+ m_tAnalogTriggerInput[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Input"));
+ m_tAnalogTriggerL[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Left"));
+ m_tAnalogTriggerR[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Right"));
+
+ m_AnalogTriggerL[i] = new wxTextCtrl(m_Controller[i], ID_TRIGGER_L, wxT(""), wxDefaultPosition, wxSize(TxtW, TxtH), wxTE_READONLY | wxTE_CENTRE);
+ m_AnalogTriggerR[i] = new wxTextCtrl(m_Controller[i], ID_TRIGGER_R, wxT(""), wxDefaultPosition, wxSize(TxtW, TxtH), wxTE_READONLY | wxTE_CENTRE);
+
+ m_AnalogTriggerL[i]->Enable(false);
+ m_AnalogTriggerR[i]->Enable(false);
+
+ m_bAnalogTriggerL[i] = new wxButton(m_Controller[i], IDB_TRIGGER_L, wxEmptyString, wxDefaultPosition, wxSize(21, 14));
+ m_bAnalogTriggerR[i] = new wxButton(m_Controller[i], IDB_TRIGGER_R, wxEmptyString, wxDefaultPosition, wxSize(21, 14));
+
+ m_TriggerType[i] = new wxComboBox(m_Controller[i], ID_TRIGGER_TYPE, StrTriggerType[0], wxDefaultPosition, wxDefaultSize, StrTriggerType, wxCB_READONLY);
+
+ m_SizeAnalogTriggerStatusBox[i] = new wxGridBagSizer(0, 0);
+ m_SizeAnalogTriggerHorizConfig[i] = new wxGridBagSizer(0, 0);
+ m_SizeAnalogTriggerVertLeft[i] = new wxBoxSizer(wxVERTICAL);
+ m_SizeAnalogTriggerVertRight[i] = new wxBoxSizer(wxVERTICAL);
+ m_SizeAnalogTriggerHorizInput[i] = new wxBoxSizer(wxHORIZONTAL);
+
+ // The status text boxes
+ m_SizeAnalogTriggerStatusBox[i]->Add(m_TriggerStatusL[i], wxGBPosition(0, 0), wxGBSpan(1, 1), (wxUP), 0);
+ m_SizeAnalogTriggerStatusBox[i]->Add(m_TriggerStatusLx[i], wxGBPosition(0, 1), wxGBSpan(1, 1), (wxUP), 0);
+ m_SizeAnalogTriggerStatusBox[i]->Add(m_TriggerStatusR[i], wxGBPosition(1, 0), wxGBSpan(1, 1), (wxUP), 0);
+ m_SizeAnalogTriggerStatusBox[i]->Add(m_TriggerStatusRx[i], wxGBPosition(1, 1), wxGBSpan(1, 1), (wxUP), 0);
+
+ m_SizeAnalogTriggerHorizConfig[i]->Add(m_tAnalogTriggerL[i], wxGBPosition(0, 0), wxGBSpan(1, 1), (wxUP), 2);
+ m_SizeAnalogTriggerHorizConfig[i]->Add(m_AnalogTriggerL[i], wxGBPosition(0, 1), wxGBSpan(1, 1), (wxLEFT | wxRIGHT), 2);
+ m_SizeAnalogTriggerHorizConfig[i]->Add(m_bAnalogTriggerL[i], wxGBPosition(0, 2), wxGBSpan(1, 1), (wxUP), 2);
+ m_SizeAnalogTriggerHorizConfig[i]->Add(m_tAnalogTriggerR[i], wxGBPosition(1, 0), wxGBSpan(1, 1), (wxUP), 4);
+ m_SizeAnalogTriggerHorizConfig[i]->Add(m_AnalogTriggerR[i], wxGBPosition(1, 1), wxGBSpan(1, 1), (wxLEFT | wxUP | wxRIGHT), 2);
+ m_SizeAnalogTriggerHorizConfig[i]->Add(m_bAnalogTriggerR[i], wxGBPosition(1, 2), wxGBSpan(1, 1), (wxUP), 5);
+
+ // The choice box and its name label
+ m_SizeAnalogTriggerHorizInput[i]->Add(m_tAnalogTriggerInput[i], 0, (wxUP), 3);
+ m_SizeAnalogTriggerHorizInput[i]->Add(m_TriggerType[i], 0, (wxLEFT), 2);
+
+ // The status text boxes
+ m_SizeAnalogTriggerVertLeft[i]->AddStretchSpacer();
+ m_SizeAnalogTriggerVertLeft[i]->Add(m_SizeAnalogTriggerStatusBox[i]);
+ m_SizeAnalogTriggerVertLeft[i]->AddStretchSpacer();
+
+ // The config grid and the input type choice box
+ m_SizeAnalogTriggerVertRight[i]->Add(m_SizeAnalogTriggerHorizConfig[i], 0, (wxUP), 2);
+ m_SizeAnalogTriggerVertRight[i]->Add(m_SizeAnalogTriggerHorizInput[i], 0, (wxUP | wxDOWN), 4);
+
+ m_gTrigger[i]->Add(m_SizeAnalogTriggerVertLeft[i], 0, wxEXPAND | (wxLEFT | wxRIGHT), 5);
+ m_gTrigger[i]->Add(m_SizeAnalogTriggerVertRight[i], 0, wxEXPAND | (wxLEFT | wxRIGHT), 5);
+
+ // --------------------------------------------------------------------
+ // Row 2 Sizers: Connected pads, tilt, triggers
+ // -----------------------------
+ m_HorizControllerTilt[i] = new wxBoxSizer(wxHORIZONTAL);
+ m_HorizControllerTilt[i]->Add(m_gJoyname[i], 0, wxALIGN_CENTER | wxEXPAND, 0);
+ m_HorizControllerTilt[i]->Add(m_gTilt[i], 0, wxEXPAND | (wxLEFT), 5);
+ m_HorizControllerTilt[i]->Add(m_gTrigger[i], 0, wxEXPAND | (wxLEFT), 5);
+
+ m_HorizControllerTiltParent[i] = new wxBoxSizer(wxBOTH);
+ m_HorizControllerTiltParent[i]->Add(m_HorizControllerTilt[i]);
+
+
+
+ // --------------------------------------------------------------------
+ // Analog sticks
+ // -----------------------------
+
+ // Status panels
+ m_TStatusLeftIn[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("In"));
+ m_TStatusLeftOut[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Out"));
+ m_TStatusRightIn[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("In"));
+ m_TStatusRightOut[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Out"));
+
+ 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);
+
+ m_AnalogLeftX[i] = new wxTextCtrl(m_Controller[i], ID_ANALOG_LEFT_X, wxT(""), wxDefaultPosition, wxSize(TxtW, TxtH), wxTE_READONLY | wxTE_CENTRE);
+ m_AnalogLeftY[i] = new wxTextCtrl(m_Controller[i], ID_ANALOG_LEFT_Y, wxT(""), wxDefaultPosition, wxSize(TxtW, TxtH), wxTE_READONLY | wxTE_CENTRE);
+ m_AnalogRightX[i] = new wxTextCtrl(m_Controller[i], ID_ANALOG_RIGHT_X, wxT(""), wxDefaultPosition, wxSize(TxtW, TxtH), wxTE_READONLY | wxTE_CENTRE);
+ m_AnalogRightY[i] = new wxTextCtrl(m_Controller[i], ID_ANALOG_RIGHT_Y, wxT(""), wxDefaultPosition, wxSize(TxtW, TxtH), wxTE_READONLY | wxTE_CENTRE);
+
+ m_AnalogLeftX[i]->Enable(false);
+ m_AnalogLeftY[i]->Enable(false);
+ m_AnalogRightX[i]->Enable(false);
+ m_AnalogRightY[i]->Enable(false);
+
+ m_bAnalogLeftX[i] = new wxButton(m_Controller[i], IDB_ANALOG_LEFT_X, wxEmptyString, wxDefaultPosition, wxSize(21, 14));
+ m_bAnalogLeftY[i] = new wxButton(m_Controller[i], IDB_ANALOG_LEFT_Y, wxEmptyString, wxDefaultPosition, wxSize(21, 14));
+ m_bAnalogRightX[i] = new wxButton(m_Controller[i], IDB_ANALOG_RIGHT_X, wxEmptyString, wxDefaultPosition, wxSize(21, 14));
+ m_bAnalogRightY[i] = new wxButton(m_Controller[i], IDB_ANALOG_RIGHT_Y, wxEmptyString, wxDefaultPosition, wxSize(21, 14));
+
+ m_SizeAnalogLeft[i] = new wxBoxSizer(wxVERTICAL); m_SizeAnalogLeftHorizX[i] = new wxBoxSizer(wxHORIZONTAL); m_SizeAnalogLeftHorizY[i] = new wxBoxSizer(wxHORIZONTAL);
+ m_SizeAnalogRight[i] = new wxBoxSizer(wxVERTICAL); m_SizeAnalogRightHorizX[i] = new wxBoxSizer(wxHORIZONTAL); m_SizeAnalogRightHorizY[i] = new wxBoxSizer(wxHORIZONTAL);
+
+ m_tAnalogX[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("X-Axis"));
+ m_tAnalogX[i + 4] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("X-Axis"));
+ m_tAnalogY[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Y-Axis"));
+ m_tAnalogY[i + 4] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Y-Axis"));
+
+ // Configuration sizers
+ m_SizeAnalogLeftHorizX[i]->Add(m_tAnalogX[i], 0, (wxUP), 2);
+ m_SizeAnalogLeftHorizX[i]->Add(m_AnalogLeftX[i], 0, (wxRIGHT), 2);
+ m_SizeAnalogLeftHorizX[i]->Add(m_bAnalogLeftX[i], 0, (wxUP), 2);
+ m_SizeAnalogLeftHorizY[i]->Add(m_tAnalogY[i], 0, (wxUP), 4);
+ m_SizeAnalogLeftHorizY[i]->Add(m_AnalogLeftY[i], 0, (wxUP | wxRIGHT), 2);
+ m_SizeAnalogLeftHorizY[i]->Add(m_bAnalogLeftY[i], 0, (wxUP), 4);
+
+ m_SizeAnalogRightHorizX[i]->Add(m_tAnalogX[i + 4], 0, (wxUP), 2);
+ m_SizeAnalogRightHorizX[i]->Add(m_AnalogRightX[i], 0, (wxRIGHT), 2);
+ m_SizeAnalogRightHorizX[i]->Add(m_bAnalogRightX[i], 0, (wxUP), 2);
+ m_SizeAnalogRightHorizY[i]->Add(m_tAnalogY[i + 4], 0, (wxUP), 4);
+ m_SizeAnalogRightHorizY[i]->Add(m_AnalogRightY[i], 0, (wxUP | wxRIGHT), 2);
+ m_SizeAnalogRightHorizY[i]->Add(m_bAnalogRightY[i], 0, (wxUP), 4);
+
+ m_SizeAnalogLeft[i]->AddStretchSpacer();
+ m_SizeAnalogLeft[i]->Add(m_SizeAnalogLeftHorizX[i], 0, (wxUP), 0);
+ m_SizeAnalogLeft[i]->Add(m_SizeAnalogLeftHorizY[i], 0, (wxUP), 0);
+ m_SizeAnalogLeft[i]->AddStretchSpacer();
+ m_SizeAnalogRight[i]->AddStretchSpacer();
+ m_SizeAnalogRight[i]->Add(m_SizeAnalogRightHorizX[i], 0, (wxUP), 0);
+ m_SizeAnalogRight[i]->Add(m_SizeAnalogRightHorizY[i], 0, (wxUP), 0);
+ m_SizeAnalogRight[i]->AddStretchSpacer();
+
+ // Status sizers
+ m_GridLeftStick[i] = new wxGridBagSizer(0, 0);
+ m_GridLeftStick[i]->Add(m_pLeftInStatus[i], wxGBPosition(0, 0), wxGBSpan(1, 1), wxALL, 0);
+ m_GridLeftStick[i]->Add(m_pLeftOutStatus[i], wxGBPosition(0, 1), wxGBSpan(1, 1), wxLEFT, 5);
+ m_GridLeftStick[i]->Add(m_TStatusLeftIn[i], wxGBPosition(1, 0), wxGBSpan(1, 1), wxALL, 0);
+ m_GridLeftStick[i]->Add(m_TStatusLeftOut[i], wxGBPosition(1, 1), wxGBSpan(1, 1), wxLEFT, 5);
+
+ m_GridRightStick[i] = new wxGridBagSizer(0, 0);
+ m_GridRightStick[i]->Add(m_pRightInStatus[i], wxGBPosition(0, 0), wxGBSpan(1, 1), wxALL, 0);
+ m_GridRightStick[i]->Add(m_pRightOutStatus[i], wxGBPosition(0, 1), wxGBSpan(1, 1), wxLEFT, 5);
+ m_GridRightStick[i]->Add(m_TStatusRightIn[i], wxGBPosition(1, 0), wxGBSpan(1, 1), wxALL, 0);
+ m_GridRightStick[i]->Add(m_TStatusRightOut[i], wxGBPosition(1, 1), wxGBSpan(1, 1), wxLEFT, 5);
+
+ m_gAnalogLeft[i] = new wxStaticBoxSizer (wxHORIZONTAL, m_Controller[i], wxT("Analog 1 (In) (Out)"));
+ m_gAnalogLeft[i]->Add(m_GridLeftStick[i], 0, (wxLEFT | wxRIGHT), 5);
+ m_gAnalogLeft[i]->Add(m_SizeAnalogLeft[i], 0, wxEXPAND | wxALIGN_CENTER_VERTICAL, 0);
+
+ m_gAnalogRight[i] = new wxStaticBoxSizer (wxHORIZONTAL, m_Controller[i], wxT("Analog 2 (In) (Out)"));
+ m_gAnalogRight[i]->Add(m_GridRightStick[i], 0, (wxLEFT | wxRIGHT), 5);
+ m_gAnalogRight[i]->Add(m_SizeAnalogRight[i], 0, wxEXPAND | wxALIGN_CENTER_VERTICAL, 0);
+
+
+ // --------------------------------------------------------------------
+ // Row 3 Sizers
+ // -----------------------------
+ m_HorizControllers[i] = new wxBoxSizer(wxHORIZONTAL);
+ //m_HorizControllers[i]->AddStretchSpacer();
+ m_HorizControllers[i]->AddSpacer(17);
+ m_HorizControllers[i]->Add(m_gAnalogLeft[i]);
+ m_HorizControllers[i]->Add(m_gAnalogRight[i], 0, (wxLEFT), 5);
+ //m_HorizControllers[i]->AddStretchSpacer();
+ ///////////////////////////
+
+
+ ////////////////////////////////////////////////////////////////////////
+ // Keyboard mapping
+ // ----------------
+
+ // --------------------------------------------------------------------
+ // Wiimote
+ // -----------------------------
+
+ m_tWmA[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("A"));
+ m_tWmB[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("B"));
+ m_tWm1[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("1"));
+ m_tWm2[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("2"));
+ m_tWmP[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("+"));
+ m_tWmM[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("- ")); // Intentional space
+ m_tWmH[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Home"));
+ m_tWmL[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Left"));
+ m_tWmR[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Right"));
+ m_tWmU[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Up"));
+ m_tWmD[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Down"));
+ m_tWmShake[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Shake"));
+ m_tWmPitchL[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Pitch Left"));
+ m_tWmPitchR[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Pitch Right"));
+
+ m_bWmA[i] = new wxButton(m_Controller[i], IDB_WM_A, wxEmptyString, wxDefaultPosition, wxSize(BtW, BtH));
+ m_bWmB[i] = new wxButton(m_Controller[i], IDB_WM_B, wxEmptyString, wxDefaultPosition, wxSize(BtW, BtH));
+ m_bWm1[i] = new wxButton(m_Controller[i], IDB_WM_1, wxEmptyString, wxDefaultPosition, wxSize(BtW, BtH));
+ m_bWm2[i] = new wxButton(m_Controller[i], IDB_WM_2, wxEmptyString, wxDefaultPosition, wxSize(BtW, BtH));
+ m_bWmP[i] = new wxButton(m_Controller[i], IDB_WM_P, wxEmptyString, wxDefaultPosition, wxSize(BtW, BtH));
+ m_bWmM[i] = new wxButton(m_Controller[i], IDB_WM_M, wxEmptyString, wxDefaultPosition, wxSize(BtW, BtH));
+ m_bWmH[i] = new wxButton(m_Controller[i], IDB_WM_H, wxEmptyString, wxDefaultPosition, wxSize(BtW, BtH));
+ m_bWmL[i] = new wxButton(m_Controller[i], IDB_WM_L, wxEmptyString, wxDefaultPosition, wxSize(BtW, BtH));
+ m_bWmR[i] = new wxButton(m_Controller[i], IDB_WM_R, wxEmptyString, wxDefaultPosition, wxSize(BtW, BtH));
+ m_bWmU[i] = new wxButton(m_Controller[i], IDB_WM_U, wxEmptyString, wxDefaultPosition, wxSize(BtW, BtH));
+ m_bWmD[i] = new wxButton(m_Controller[i], IDB_WM_D, wxEmptyString, wxDefaultPosition, wxSize(BtW, BtH));
+ m_bWmShake[i] = new wxButton(m_Controller[i], IDB_WM_SHAKE, wxEmptyString, wxDefaultPosition, wxSize(BtW, BtH));
+ m_bWmPitchL[i] = new wxButton(m_Controller[i], IDB_WM_PITCH_L, wxEmptyString, wxDefaultPosition, wxSize(BtW, BtH));
+ m_bWmPitchR[i] = new wxButton(m_Controller[i], IDB_WM_PITCH_R, wxEmptyString, wxDefaultPosition, wxSize(BtW, BtH));
+
+ // Set small font
+ m_bWmA[i]->SetFont(m_SmallFont); m_bWmB[i]->SetFont(m_SmallFont);
+ m_bWm1[i]->SetFont(m_SmallFont); m_bWm2[i]->SetFont(m_SmallFont);
+ m_bWmP[i]->SetFont(m_SmallFont); m_bWmM[i]->SetFont(m_SmallFont); m_bWmH[i]->SetFont(m_SmallFont);
+ m_bWmL[i]->SetFont(m_SmallFont); m_bWmR[i]->SetFont(m_SmallFont);
+ m_bWmU[i]->SetFont(m_SmallFont); m_bWmD[i]->SetFont(m_SmallFont);
+ m_bWmShake[i]->SetFont(m_SmallFont);
+ m_bWmPitchL[i]->SetFont(m_SmallFont); m_bWmPitchR[i]->SetFont(m_SmallFont);
+
+ // Sizers
+ m_SWmVertLeft[i] = new wxBoxSizer(wxVERTICAL); m_SWmVertRight[i] = new wxBoxSizer(wxVERTICAL);
+ m_SWmA[i] = new wxBoxSizer(wxHORIZONTAL); m_SWmB[i] = new wxBoxSizer(wxHORIZONTAL);
+ m_SWm1[i] = new wxBoxSizer(wxHORIZONTAL); m_SWm2[i] = new wxBoxSizer(wxHORIZONTAL);
+ m_SWmP[i] = new wxBoxSizer(wxHORIZONTAL); m_SWmM[i] = new wxBoxSizer(wxHORIZONTAL); m_SWmH[i] = new wxBoxSizer(wxHORIZONTAL);
+ m_SWmL[i] = new wxBoxSizer(wxHORIZONTAL); m_SWmR[i] = new wxBoxSizer(wxHORIZONTAL);
+ m_SWmU[i] = new wxBoxSizer(wxHORIZONTAL); m_SWmD[i] = new wxBoxSizer(wxHORIZONTAL);
+ m_SWmShake[i] = new wxBoxSizer(wxHORIZONTAL);
+ m_SWmPitchL[i] = new wxBoxSizer(wxHORIZONTAL); m_SWmPitchR[i] = new wxBoxSizer(wxHORIZONTAL);
+
+ m_SWmA[i]->Add(m_tWmA[i], 0, (wxUP), 4); m_SWmA[i]->Add(m_bWmA[i], 0, (wxLEFT), 2);
+ m_SWmB[i]->Add(m_tWmB[i], 0, (wxUP), 4); m_SWmB[i]->Add(m_bWmB[i], 0, (wxLEFT), 2);
+ m_SWm1[i]->Add(m_tWm1[i], 0, (wxUP), 4); m_SWm1[i]->Add(m_bWm1[i], 0, (wxLEFT), 2);
+ m_SWm2[i]->Add(m_tWm2[i], 0, (wxUP), 4); m_SWm2[i]->Add(m_bWm2[i], 0, (wxLEFT), 2);
+ m_SWmP[i]->Add(m_tWmP[i], 0, (wxUP), 4); m_SWmP[i]->Add(m_bWmP[i], 0, (wxLEFT), 2);
+ m_SWmM[i]->Add(m_tWmM[i], 0, (wxUP), 4); m_SWmM[i]->Add(m_bWmM[i], 0, (wxLEFT), 2);
+ m_SWmH[i]->Add(m_tWmH[i], 0, (wxUP), 4); m_SWmH[i]->Add(m_bWmH[i], 0, (wxLEFT), 2);
+ m_SWmL[i]->Add(m_tWmL[i], 0, (wxUP), 4); m_SWmL[i]->Add(m_bWmL[i], 0, (wxLEFT), 2);
+ m_SWmR[i]->Add(m_tWmR[i], 0, (wxUP), 4); m_SWmR[i]->Add(m_bWmR[i], 0, (wxLEFT), 2);
+ m_SWmU[i]->Add(m_tWmU[i], 0, (wxUP), 4); m_SWmU[i]->Add(m_bWmU[i], 0, (wxLEFT), 2);
+ m_SWmD[i]->Add(m_tWmD[i], 0, (wxUP), 4); m_SWmD[i]->Add(m_bWmD[i], 0, (wxLEFT), 2);
+ m_SWmShake[i]->Add(m_tWmShake[i], 0, (wxUP), 4); m_SWmShake[i]->Add(m_bWmShake[i], 0, (wxLEFT), 2);
+ m_SWmPitchL[i]->Add(m_tWmPitchL[i], 0, (wxUP), 4); m_SWmPitchL[i]->Add(m_bWmPitchL[i], 0, (wxLEFT), 2);
+ m_SWmPitchR[i]->Add(m_tWmPitchR[i], 0, (wxUP), 4); m_SWmPitchR[i]->Add(m_bWmPitchR[i], 0, (wxLEFT), 2);
+
+ m_SWmVertLeft[i]->Add(m_SWmA[i], 0, wxALIGN_RIGHT | (wxALL), 1);
+ m_SWmVertLeft[i]->Add(m_SWmB[i], 0, wxALIGN_RIGHT | (wxLEFT | wxRIGHT | wxDOWN), 1);
+ m_SWmVertLeft[i]->Add(m_SWm1[i], 0, wxALIGN_RIGHT | (wxLEFT | wxRIGHT | wxDOWN), 1);
+ m_SWmVertLeft[i]->Add(m_SWm2[i], 0, wxALIGN_RIGHT | (wxLEFT | wxRIGHT | wxDOWN), 1);
+ m_SWmVertLeft[i]->Add(m_SWmP[i], 0, wxALIGN_RIGHT | (wxLEFT | wxRIGHT | wxDOWN), 1);
+ m_SWmVertLeft[i]->Add(m_SWmM[i], 0, wxALIGN_RIGHT | (wxLEFT | wxRIGHT | wxDOWN), 1);
+ m_SWmVertLeft[i]->Add(m_SWmH[i], 0, wxALIGN_RIGHT | (wxLEFT | wxRIGHT | wxDOWN), 1);
+
+ m_SWmVertRight[i]->Add(m_SWmShake[i], 0, wxALIGN_RIGHT | (wxALL), 1);
+ //m_SWmVertRight[i]->AddSpacer(3);
+ m_SWmVertRight[i]->Add(m_SWmPitchL[i], 0, wxALIGN_RIGHT | (wxLEFT | wxRIGHT | wxDOWN), 1);
+ m_SWmVertRight[i]->Add(m_SWmPitchR[i], 0, wxALIGN_RIGHT | (wxLEFT | wxRIGHT | wxDOWN), 1);
+ //m_SWmVertRight[i]->AddSpacer(3);
+ m_SWmVertRight[i]->Add(m_SWmL[i], 0, wxALIGN_RIGHT | (wxLEFT | wxRIGHT | wxDOWN), 1);
+ m_SWmVertRight[i]->Add(m_SWmR[i], 0, wxALIGN_RIGHT | (wxLEFT | wxRIGHT | wxDOWN), 1);
+ m_SWmVertRight[i]->Add(m_SWmU[i], 0, wxALIGN_RIGHT | (wxLEFT | wxRIGHT | wxDOWN), 1);
+ m_SWmVertRight[i]->Add(m_SWmD[i], 0, wxALIGN_RIGHT | (wxLEFT | wxRIGHT | wxDOWN), 1);
+
+ m_gWiimote[i] = new wxStaticBoxSizer (wxHORIZONTAL, m_Controller[i], wxT("Wiimote"));
+ m_gWiimote[i]->Add(m_SWmVertLeft[i], 0, wxALIGN_RIGHT | (wxALL), 0);
+ m_gWiimote[i]->Add(m_SWmVertRight[i], 0, wxALIGN_RIGHT | (wxLEFT), 5);
+ m_gWiimote[i]->AddSpacer(1);
+
+ // --------------------------------------------------------------------
+ // Nunchuck
+ // -----------------------------
+
+ // Stick controls
+ m_NunchuckTextStick[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Stick"));
+ m_NunchuckComboStick[i] = new wxComboBox(m_Controller[i], IDCB_NUNCHUCK_STICK, StrNunchuck[0], wxDefaultPosition, wxDefaultSize, StrNunchuck, wxCB_READONLY);
+
+ m_tNcZ[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Z"));
+ m_tNcC[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("C"));
+ m_tNcL[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Left"));
+ m_tNcR[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Right"));
+ m_tNcU[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Up"));
+ m_tNcD[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Down"));
+ m_tNcShake[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Shake"));
+
+ m_bNcZ[i] = new wxButton(m_Controller[i], IDB_NC_Z, wxEmptyString, wxDefaultPosition, wxSize(BtW, BtH));
+ m_bNcC[i] = new wxButton(m_Controller[i], IDB_NC_C, wxEmptyString, wxDefaultPosition, wxSize(BtW, BtH));
+ m_bNcL[i] = new wxButton(m_Controller[i], IDB_NC_L, wxEmptyString, wxDefaultPosition, wxSize(BtW, BtH));
+ m_bNcR[i] = new wxButton(m_Controller[i], IDB_NC_R, wxEmptyString, wxDefaultPosition, wxSize(BtW, BtH));
+ m_bNcU[i] = new wxButton(m_Controller[i], IDB_NC_U, wxEmptyString, wxDefaultPosition, wxSize(BtW, BtH));
+ m_bNcD[i] = new wxButton(m_Controller[i], IDB_NC_D, wxEmptyString, wxDefaultPosition, wxSize(BtW, BtH));
+ m_bNcShake[i] = new wxButton(m_Controller[i], IDB_NC_SHAKE, wxEmptyString, wxDefaultPosition, wxSize(BtW, BtH));
+
+ // Set small font
+ m_bNcShake[i]->SetFont(m_SmallFont);
+ m_bNcZ[i]->SetFont(m_SmallFont);
+ m_bNcC[i]->SetFont(m_SmallFont);
+ m_bNcL[i]->SetFont(m_SmallFont); m_bNcR[i]->SetFont(m_SmallFont);
+ m_bNcU[i]->SetFont(m_SmallFont); m_bNcD[i]->SetFont(m_SmallFont);
+ m_bNcShake[i]->SetFont(m_SmallFont);
+
+ // Sizers
+ m_NunchuckStick[i] = new wxBoxSizer(wxHORIZONTAL);
+ m_NunchuckStick[i]->Add(m_NunchuckTextStick[i], 0, (wxUP), 4);
+ m_NunchuckStick[i]->Add(m_NunchuckComboStick[i], 0, (wxLEFT), 2);
+
+ m_SNcZ[i] = new wxBoxSizer(wxHORIZONTAL); m_SNcC[i] = new wxBoxSizer(wxHORIZONTAL);
+ m_SNcL[i] = new wxBoxSizer(wxHORIZONTAL); m_SNcR[i] = new wxBoxSizer(wxHORIZONTAL);
+ m_SNcU[i] = new wxBoxSizer(wxHORIZONTAL); m_SNcD[i] = new wxBoxSizer(wxHORIZONTAL);
+ m_SNcShake[i] = new wxBoxSizer(wxHORIZONTAL);
+
+ m_SNcZ[i]->Add(m_tNcZ[i], 0, wxALIGN_RIGHT | (wxUP), 4); m_SNcZ[i]->Add(m_bNcZ[i], 0, wxALIGN_RIGHT | (wxLEFT), 2);
+ m_SNcC[i]->Add(m_tNcC[i], 0, wxALIGN_RIGHT | (wxUP), 4); m_SNcC[i]->Add(m_bNcC[i], 0, wxALIGN_RIGHT | (wxLEFT), 2);
+ m_SNcL[i]->Add(m_tNcL[i], 0, wxALIGN_RIGHT | (wxUP), 4); m_SNcL[i]->Add(m_bNcL[i], 0, wxALIGN_RIGHT | (wxLEFT), 2);
+ m_SNcR[i]->Add(m_tNcR[i], 0, wxALIGN_RIGHT | (wxUP), 4); m_SNcR[i]->Add(m_bNcR[i], 0, wxALIGN_RIGHT | (wxLEFT), 2);
+ m_SNcU[i]->Add(m_tNcU[i], 0, wxALIGN_RIGHT | (wxUP), 4); m_SNcU[i]->Add(m_bNcU[i], 0, wxALIGN_RIGHT | (wxLEFT), 2);
+ m_SNcD[i]->Add(m_tNcD[i], 0, wxALIGN_RIGHT | (wxUP), 4); m_SNcD[i]->Add(m_bNcD[i], 0, wxALIGN_RIGHT | (wxLEFT), 2);
+ m_SNcShake[i]->Add(m_tNcShake[i], 0, wxALIGN_RIGHT | (wxUP), 4); m_SNcShake[i]->Add(m_bNcShake[i], 0, wxALIGN_RIGHT | (wxLEFT), 2);
+
+ // The parent sizer
+ m_gNunchuck[i] = new wxStaticBoxSizer (wxVERTICAL, m_Controller[i], wxT("Nunchuck"));
+ m_gNunchuck[i]->Add(m_NunchuckStick[i], 0, wxALIGN_CENTER | (wxALL), 2);
+ m_gNunchuck[i]->AddSpacer(2);
+ m_gNunchuck[i]->Add(m_SNcShake[i], 0, wxALIGN_RIGHT | (wxALL), 1);
+ m_gNunchuck[i]->Add(m_SNcZ[i], 0, wxALIGN_RIGHT | (wxLEFT | wxRIGHT | wxDOWN), 1);
+ m_gNunchuck[i]->Add(m_SNcC[i], 0, wxALIGN_RIGHT | (wxLEFT | wxRIGHT | wxDOWN), 1);
+ m_gNunchuck[i]->Add(m_SNcL[i], 0, wxALIGN_RIGHT | (wxLEFT | wxRIGHT | wxDOWN), 1);
+ m_gNunchuck[i]->Add(m_SNcR[i], 0, wxALIGN_RIGHT | (wxLEFT | wxRIGHT | wxDOWN), 1);
+ m_gNunchuck[i]->Add(m_SNcU[i], 0, wxALIGN_RIGHT | (wxLEFT | wxRIGHT | wxDOWN), 1);
+ m_gNunchuck[i]->Add(m_SNcD[i], 0, wxALIGN_RIGHT | (wxLEFT | wxRIGHT | wxDOWN), 1);
+
+ //Set values
+ m_NunchuckComboStick[i]->SetSelection(g_Config.Nunchuck.Type);
+
+ // --------------------------------------------------------------------
+ // Classic Controller
+ // -----------------------------
+
+ // Stick controls
+ m_CcTextLeftStick[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Left stick"));
+ m_CcComboLeftStick[i] = new wxComboBox(m_Controller[i], IDCB_CC_LEFT_STICK, StrNunchuck[0], wxDefaultPosition, wxDefaultSize, StrNunchuck, wxCB_READONLY);
+ m_CcTextRightStick[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Right stick"));
+ m_CcComboRightStick[i] = new wxComboBox(m_Controller[i], IDCB_CC_RIGHT_STICK, StrNunchuck[0], wxDefaultPosition, wxDefaultSize, StrNunchuck, wxCB_READONLY);
+ m_CcTextTriggers[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Triggers"));
+ m_CcComboTriggers[i] = new wxComboBox(m_Controller[i], IDCB_CC_TRIGGERS, StrCcTriggers[0], wxDefaultPosition, wxDefaultSize, StrCcTriggers, wxCB_READONLY);
+
+ m_tCcA[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("A"));
+ m_tCcB[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("B"));
+ m_tCcX[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("X"));
+ m_tCcY[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Y"));
+ m_tCcP[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("+"));
+ m_tCcM[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("- "));
+ m_tCcH[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Home"));
+
+ m_tCcTl[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Left trigger"));
+ m_tCcZl[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Left Z"));
+ m_tCcZr[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Right Z"));
+ m_tCcTr[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Right trigger"));
+
+ m_tCcDl[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Digital Left")); // Digital pad
+ m_tCcDu[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Digital Up"));
+ m_tCcDr[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Digital Right"));
+ m_tCcDd[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Digital Down"));
+ m_tCcLl[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("L Left")); // Left analog stick
+ m_tCcLu[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("L Up"));
+ m_tCcLr[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("L Right"));
+ m_tCcLd[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("L Down"));
+ m_tCcRl[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("R Left")); // Right analog stick
+ m_tCcRu[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("R Up"));
+ m_tCcRr[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("R Right"));
+ m_tCcRd[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("R Down"));
+
+ m_bCcA[i] = new wxButton(m_Controller[i], IDB_CC_A, wxEmptyString, wxDefaultPosition, wxSize(BtW, BtH));
+ m_bCcB[i] = new wxButton(m_Controller[i], IDB_CC_B, wxEmptyString, wxDefaultPosition, wxSize(BtW, BtH));
+ m_bCcX[i] = new wxButton(m_Controller[i], IDB_CC_X, wxEmptyString, wxDefaultPosition, wxSize(BtW, BtH));
+ m_bCcY[i] = new wxButton(m_Controller[i], IDB_CC_Y, wxEmptyString, wxDefaultPosition, wxSize(BtW, BtH));
+ m_bCcP[i] = new wxButton(m_Controller[i], IDB_CC_P, wxEmptyString, wxDefaultPosition, wxSize(BtW, BtH));
+ m_bCcM[i] = new wxButton(m_Controller[i], IDB_CC_M, wxEmptyString, wxDefaultPosition, wxSize(BtW, BtH));
+ m_bCcH[i] = new wxButton(m_Controller[i], IDB_CC_H, wxEmptyString, wxDefaultPosition, wxSize(BtW, BtH));
+
+ m_bCcTl[i] = new wxButton(m_Controller[i], IDB_CC_TL, wxEmptyString, wxDefaultPosition, wxSize(BtW, BtH));
+ m_bCcZl[i] = new wxButton(m_Controller[i], IDB_CC_ZL, wxEmptyString, wxDefaultPosition, wxSize(BtW, BtH));
+ m_bCcZr[i] = new wxButton(m_Controller[i], IDB_CC_ZR, wxEmptyString, wxDefaultPosition, wxSize(BtW, BtH));
+ m_bCcTr[i] = new wxButton(m_Controller[i], IDB_CC_TR, wxEmptyString, wxDefaultPosition, wxSize(BtW, BtH));
+
+ m_bCcDl[i] = new wxButton(m_Controller[i], IDB_CC_DL, wxEmptyString, wxDefaultPosition, wxSize(BtW, BtH)); // Digital pad
+ m_bCcDu[i] = new wxButton(m_Controller[i], IDB_CC_DU, wxEmptyString, wxDefaultPosition, wxSize(BtW, BtH));
+ m_bCcDr[i] = new wxButton(m_Controller[i], IDB_CC_DR, wxEmptyString, wxDefaultPosition, wxSize(BtW, BtH));
+ m_bCcDd[i] = new wxButton(m_Controller[i], IDB_CC_DD, wxEmptyString, wxDefaultPosition, wxSize(BtW, BtH));
+ m_bCcLl[i] = new wxButton(m_Controller[i], IDB_CC_LL, wxEmptyString, wxDefaultPosition, wxSize(BtW, BtH)); // Left analog stick
+ m_bCcLu[i] = new wxButton(m_Controller[i], IDB_CC_LU, wxEmptyString, wxDefaultPosition, wxSize(BtW, BtH));
+ m_bCcLr[i] = new wxButton(m_Controller[i], IDB_CC_LR, wxEmptyString, wxDefaultPosition, wxSize(BtW, BtH));
+ m_bCcLd[i] = new wxButton(m_Controller[i], IDB_CC_LD, wxEmptyString, wxDefaultPosition, wxSize(BtW, BtH));
+ m_bCcRl[i] = new wxButton(m_Controller[i], IDB_CC_RL, wxEmptyString, wxDefaultPosition, wxSize(BtW, BtH)); // Right analog stick
+ m_bCcRu[i] = new wxButton(m_Controller[i], IDB_CC_RU, wxEmptyString, wxDefaultPosition, wxSize(BtW, BtH));
+ m_bCcRr[i] = new wxButton(m_Controller[i], IDB_CC_RR, wxEmptyString, wxDefaultPosition, wxSize(BtW, BtH));
+ m_bCcRd[i] = new wxButton(m_Controller[i], IDB_CC_RD, wxEmptyString, wxDefaultPosition, wxSize(BtW, BtH));
+
+ // Set small font
+ m_bCcA[i]->SetFont(m_SmallFont); m_bCcB[i]->SetFont(m_SmallFont);
+ m_bCcX[i]->SetFont(m_SmallFont); m_bCcY[i]->SetFont(m_SmallFont);
+ m_bCcP[i]->SetFont(m_SmallFont); m_bCcM[i]->SetFont(m_SmallFont); m_bCcH[i]->SetFont(m_SmallFont);
+ m_bCcTl[i]->SetFont(m_SmallFont); m_bCcZl[i]->SetFont(m_SmallFont); m_bCcZr[i]->SetFont(m_SmallFont); m_bCcTr[i]->SetFont(m_SmallFont);
+ m_bCcDl[i]->SetFont(m_SmallFont); m_bCcDu[i]->SetFont(m_SmallFont); m_bCcDr[i]->SetFont(m_SmallFont); m_bCcDd[i]->SetFont(m_SmallFont);
+ m_bCcLl[i]->SetFont(m_SmallFont); m_bCcLu[i]->SetFont(m_SmallFont); m_bCcLr[i]->SetFont(m_SmallFont); m_bCcLd[i]->SetFont(m_SmallFont);
+ m_bCcRl[i]->SetFont(m_SmallFont); m_bCcRu[i]->SetFont(m_SmallFont); m_bCcRr[i]->SetFont(m_SmallFont); m_bCcRd[i]->SetFont(m_SmallFont);
+
+ // Sizers
+ m_SCcLeftStick[i] = new wxBoxSizer(wxHORIZONTAL);
+ m_SCcLeftStick[i]->Add(m_CcTextLeftStick[i], 0, (wxUP), 4);
+ m_SCcLeftStick[i]->Add(m_CcComboLeftStick[i], 0, (wxLEFT), 2);
+
+ m_SCcRightStick[i] = new wxBoxSizer(wxHORIZONTAL);
+ m_SCcRightStick[i]->Add(m_CcTextRightStick[i], 0, (wxUP), 4);
+ m_SCcRightStick[i]->Add(m_CcComboRightStick[i], 0, (wxLEFT), 2);
+
+ m_SCcTriggers[i] = new wxBoxSizer(wxHORIZONTAL);
+ m_SCcTriggers[i]->Add(m_CcTextTriggers[i], 0, (wxUP), 4);
+ m_SCcTriggers[i]->Add(m_CcComboTriggers[i], 0, (wxLEFT), 2);
+
+ m_SCcA[i] = new wxBoxSizer(wxHORIZONTAL); m_SCcB[i] = new wxBoxSizer(wxHORIZONTAL);
+ m_SCcX[i] = new wxBoxSizer(wxHORIZONTAL); m_SCcY[i] = new wxBoxSizer(wxHORIZONTAL);
+ m_SCcP[i] = new wxBoxSizer(wxHORIZONTAL); m_SCcM[i] = new wxBoxSizer(wxHORIZONTAL); m_SCcH[i] = new wxBoxSizer(wxHORIZONTAL);
+ m_SCcTl[i] = new wxBoxSizer(wxHORIZONTAL); m_SCcZl[i] = new wxBoxSizer(wxHORIZONTAL); m_SCcZr[i] = new wxBoxSizer(wxHORIZONTAL); m_SCcTr[i] = new wxBoxSizer(wxHORIZONTAL);
+ m_SCcDl[i] = new wxBoxSizer(wxHORIZONTAL); m_SCcDu[i] = new wxBoxSizer(wxHORIZONTAL); m_SCcDr[i] = new wxBoxSizer(wxHORIZONTAL); m_SCcDd[i] = new wxBoxSizer(wxHORIZONTAL);
+ m_SCcLl[i] = new wxBoxSizer(wxHORIZONTAL); m_SCcLu[i] = new wxBoxSizer(wxHORIZONTAL); m_SCcLr[i] = new wxBoxSizer(wxHORIZONTAL); m_SCcLd[i] = new wxBoxSizer(wxHORIZONTAL);
+ m_SCcRl[i] = new wxBoxSizer(wxHORIZONTAL); m_SCcRu[i] = new wxBoxSizer(wxHORIZONTAL); m_SCcRr[i] = new wxBoxSizer(wxHORIZONTAL); m_SCcRd[i] = new wxBoxSizer(wxHORIZONTAL);
+
+ m_SCcA[i]->Add(m_tCcA[i], 0, wxALIGN_RIGHT | (wxUP), 4); m_SCcA[i]->Add(m_bCcA[i], 0, wxALIGN_RIGHT | (wxLEFT), 2);
+ m_SCcB[i]->Add(m_tCcB[i], 0, wxALIGN_RIGHT | (wxUP), 4); m_SCcB[i]->Add(m_bCcB[i], 0, wxALIGN_RIGHT | (wxLEFT), 2);
+ m_SCcX[i]->Add(m_tCcX[i], 0, wxALIGN_RIGHT | (wxUP), 4); m_SCcX[i]->Add(m_bCcX[i], 0, wxALIGN_RIGHT | (wxLEFT), 2);
+ m_SCcY[i]->Add(m_tCcY[i], 0, wxALIGN_RIGHT | (wxUP), 4); m_SCcY[i]->Add(m_bCcY[i], 0, wxALIGN_RIGHT | (wxLEFT), 2);
+ m_SCcP[i]->Add(m_tCcP[i], 0, wxALIGN_RIGHT | (wxUP), 4); m_SCcP[i]->Add(m_bCcP[i], 0, wxALIGN_RIGHT | (wxLEFT), 2);
+ m_SCcM[i]->Add(m_tCcM[i], 0, wxALIGN_RIGHT | (wxUP), 4); m_SCcM[i]->Add(m_bCcM[i], 0, wxALIGN_RIGHT | (wxLEFT), 2);
+ m_SCcH[i]->Add(m_tCcH[i], 0, wxALIGN_RIGHT | (wxUP), 4); m_SCcH[i]->Add(m_bCcH[i], 0, wxALIGN_RIGHT | (wxLEFT), 2);
+ m_SCcTl[i]->Add(m_tCcTl[i], 0, wxALIGN_RIGHT | (wxUP), 4); m_SCcTl[i]->Add(m_bCcTl[i], 0, wxALIGN_RIGHT | (wxLEFT), 2);
+ m_SCcZl[i]->Add(m_tCcZl[i], 0, wxALIGN_RIGHT | (wxUP), 4); m_SCcZl[i]->Add(m_bCcZl[i], 0, wxALIGN_RIGHT | (wxLEFT), 2);
+ m_SCcZr[i]->Add(m_tCcZr[i], 0, wxALIGN_RIGHT | (wxUP), 4); m_SCcZr[i]->Add(m_bCcZr[i], 0, wxALIGN_RIGHT | (wxLEFT), 2);
+ m_SCcTr[i]->Add(m_tCcTr[i], 0, wxALIGN_RIGHT | (wxUP), 4); m_SCcTr[i]->Add(m_bCcTr[i], 0, wxALIGN_RIGHT | (wxLEFT), 2);
+
+ m_SCcDl[i]->Add(m_tCcDl[i], 0, wxALIGN_RIGHT | (wxUP), 4); m_SCcDl[i]->Add(m_bCcDl[i], 0, wxALIGN_RIGHT | (wxLEFT), 2);
+ m_SCcDu[i]->Add(m_tCcDu[i], 0, wxALIGN_RIGHT | (wxUP), 4); m_SCcDu[i]->Add(m_bCcDu[i], 0, wxALIGN_RIGHT | (wxLEFT), 2);
+ m_SCcDr[i]->Add(m_tCcDr[i], 0, wxALIGN_RIGHT | (wxUP), 4); m_SCcDr[i]->Add(m_bCcDr[i], 0, wxALIGN_RIGHT | (wxLEFT), 2);
+ m_SCcDd[i]->Add(m_tCcDd[i], 0, wxALIGN_RIGHT | (wxUP), 4); m_SCcDd[i]->Add(m_bCcDd[i], 0, wxALIGN_RIGHT | (wxLEFT), 2);
+
+ m_SCcLl[i]->Add(m_tCcLl[i], 0, wxALIGN_RIGHT | (wxUP), 4); m_SCcLl[i]->Add(m_bCcLl[i], 0, wxALIGN_RIGHT | (wxLEFT), 2);
+ m_SCcLu[i]->Add(m_tCcLu[i], 0, wxALIGN_RIGHT | (wxUP), 4); m_SCcLu[i]->Add(m_bCcLu[i], 0, wxALIGN_RIGHT | (wxLEFT), 2);
+ m_SCcLr[i]->Add(m_tCcLr[i], 0, wxALIGN_RIGHT | (wxUP), 4); m_SCcLr[i]->Add(m_bCcLr[i], 0, wxALIGN_RIGHT | (wxLEFT), 2);
+ m_SCcLd[i]->Add(m_tCcLd[i], 0, wxALIGN_RIGHT | (wxUP), 4); m_SCcLd[i]->Add(m_bCcLd[i], 0, wxALIGN_RIGHT | (wxLEFT), 2);
+
+ m_SCcRl[i]->Add(m_tCcRl[i], 0, wxALIGN_RIGHT | (wxUP), 4); m_SCcRl[i]->Add(m_bCcRl[i], 0, wxALIGN_RIGHT | (wxLEFT), 2);
+ m_SCcRu[i]->Add(m_tCcRu[i], 0, wxALIGN_RIGHT | (wxUP), 4); m_SCcRu[i]->Add(m_bCcRu[i], 0, wxALIGN_RIGHT | (wxLEFT), 2);
+ m_SCcRr[i]->Add(m_tCcRr[i], 0, wxALIGN_RIGHT | (wxUP), 4); m_SCcRr[i]->Add(m_bCcRr[i], 0, wxALIGN_RIGHT | (wxLEFT), 2);
+ m_SCcRd[i]->Add(m_tCcRd[i], 0, wxALIGN_RIGHT | (wxUP), 4); m_SCcRd[i]->Add(m_bCcRd[i], 0, wxALIGN_RIGHT | (wxLEFT), 2);
+
+ // The left parent
+ m_SCcVertLeft[i] = new wxBoxSizer(wxVERTICAL);
+ m_SCcVertLeft[i]->Add(m_SCcLeftStick[i], 0, wxALIGN_RIGHT | (wxALL), 2);
+ m_SCcVertLeft[i]->Add(m_SCcRightStick[i], 0, wxALIGN_RIGHT | (wxLEFT | wxRIGHT | wxDOWN), 2);
+ m_SCcVertLeft[i]->AddSpacer(2);
+ m_SCcVertLeft[i]->Add(m_SCcDl[i], 0, wxALIGN_RIGHT | (wxLEFT | wxRIGHT | wxDOWN), 1);
+ m_SCcVertLeft[i]->Add(m_SCcDu[i], 0, wxALIGN_RIGHT | (wxLEFT | wxRIGHT | wxDOWN), 1);
+ m_SCcVertLeft[i]->Add(m_SCcDr[i], 0, wxALIGN_RIGHT | (wxLEFT | wxRIGHT | wxDOWN), 1);
+ m_SCcVertLeft[i]->Add(m_SCcDd[i], 0, wxALIGN_RIGHT | (wxLEFT | wxRIGHT | wxDOWN), 1);
+ m_SCcVertLeft[i]->Add(m_SCcTl[i], 0, wxALIGN_RIGHT | (wxLEFT | wxRIGHT | wxDOWN), 1);
+ m_SCcVertLeft[i]->Add(m_SCcTr[i], 0, wxALIGN_RIGHT | (wxLEFT | wxRIGHT | wxDOWN), 1);
+
+ // The middle parent
+ m_SCcVertMiddle[i] = new wxBoxSizer(wxVERTICAL);
+ m_SCcVertMiddle[i]->Add(m_SCcTriggers[i], 0, wxALIGN_RIGHT | (wxALL), 1);
+ m_SCcVertLeft[i]->AddSpacer(2);
+ m_SCcVertMiddle[i]->Add(m_SCcLl[i], 0, wxALIGN_RIGHT | (wxLEFT | wxRIGHT | wxDOWN), 1);
+ m_SCcVertMiddle[i]->Add(m_SCcLu[i], 0, wxALIGN_RIGHT | (wxLEFT | wxRIGHT | wxDOWN), 1);
+ m_SCcVertMiddle[i]->Add(m_SCcLr[i], 0, wxALIGN_RIGHT | (wxLEFT | wxRIGHT | wxDOWN), 1);
+ m_SCcVertMiddle[i]->Add(m_SCcLd[i], 0, wxALIGN_RIGHT | (wxLEFT | wxRIGHT | wxDOWN), 1);
+ m_SCcVertMiddle[i]->Add(m_SCcRl[i], 0, wxALIGN_RIGHT | (wxLEFT | wxRIGHT | wxDOWN), 1);
+ m_SCcVertMiddle[i]->Add(m_SCcRd[i], 0, wxALIGN_RIGHT | (wxLEFT | wxRIGHT | wxDOWN), 1);
+ m_SCcVertMiddle[i]->Add(m_SCcRr[i], 0, wxALIGN_RIGHT | (wxLEFT | wxRIGHT | wxDOWN), 1);
+ m_SCcVertMiddle[i]->Add(m_SCcRu[i], 0, wxALIGN_RIGHT | (wxLEFT | wxRIGHT | wxDOWN), 1);
+
+ // The right parent
+ m_SCcVertRight[i] = new wxBoxSizer(wxVERTICAL);
+ m_SCcVertRight[i]->Add(m_SCcA[i], 0, wxALIGN_RIGHT | (wxALL), 1);
+ m_SCcVertRight[i]->Add(m_SCcB[i], 0, wxALIGN_RIGHT | (wxLEFT | wxRIGHT | wxDOWN), 1);
+ m_SCcVertRight[i]->Add(m_SCcX[i], 0, wxALIGN_RIGHT | (wxLEFT | wxRIGHT | wxDOWN), 1);
+ m_SCcVertRight[i]->Add(m_SCcY[i], 0, wxALIGN_RIGHT | (wxLEFT | wxRIGHT | wxDOWN), 1);
+ m_SCcVertRight[i]->Add(m_SCcP[i], 0, wxALIGN_RIGHT | (wxLEFT | wxRIGHT | wxDOWN), 1);
+ m_SCcVertRight[i]->Add(m_SCcM[i], 0, wxALIGN_RIGHT | (wxLEFT | wxRIGHT | wxDOWN), 1);
+ m_SCcVertRight[i]->Add(m_SCcH[i], 0, wxALIGN_RIGHT | (wxLEFT | wxRIGHT | wxDOWN), 1);
+ m_SCcVertRight[i]->Add(m_SCcZl[i], 0, wxALIGN_RIGHT | (wxLEFT | wxRIGHT | wxDOWN), 1);
+ m_SCcVertRight[i]->Add(m_SCcZr[i], 0, wxALIGN_RIGHT | (wxLEFT | wxRIGHT | wxDOWN), 1);
+
+
+ // The parent sizer
+ m_gClassicController[i] = new wxStaticBoxSizer (wxHORIZONTAL, m_Controller[i], wxT("Classic Controller"));
+ m_gClassicController[i]->Add(m_SCcVertLeft[i], 0, wxALIGN_RIGHT | (wxLEFT | wxRIGHT | wxDOWN), 1);
+ m_gClassicController[i]->Add(m_SCcVertMiddle[i], 0, wxALIGN_RIGHT | (wxLEFT | wxRIGHT | wxDOWN), 1);
+ m_gClassicController[i]->Add(m_SCcVertRight[i], 0, wxALIGN_RIGHT | (wxLEFT | wxRIGHT | wxDOWN), 1);
+
+ //Set values
+ m_CcComboLeftStick[i]->SetSelection(g_Config.ClassicController.LType);
+ m_CcComboRightStick[i]->SetSelection(g_Config.ClassicController.RType);
+ m_CcComboTriggers[i]->SetSelection(g_Config.ClassicController.TType);
+
+ // --------------------------------------------------------------------
+ // Row 4 Sizers
+ // -----------------------------
+ m_HorizControllerMapping[i] = new wxBoxSizer(wxHORIZONTAL);
+ m_HorizControllerMapping[i]->AddStretchSpacer();
+ m_HorizControllerMapping[i]->Add(m_gWiimote[i]);
+ m_HorizControllerMapping[i]->Add(m_gNunchuck[i], 0, (wxLEFT), 5);
+ m_HorizControllerMapping[i]->Add(m_gClassicController[i], 0, (wxLEFT), 5);
+ m_HorizControllerMapping[i]->AddStretchSpacer();
+ ///////////////////////////
+
+
+ ////////////////////////////////////////////////////////////////
+ // Set up sizers and layout
+ // ----------------
+ m_SizeParent[i] = new wxBoxSizer(wxVERTICAL);
+ m_SizeParent[i]->Add(m_SizeBasicGeneral[i], 0, wxBORDER_STATIC | wxEXPAND | (wxALL), 5);
+ m_SizeParent[i]->Add(m_HorizControllerTiltParent[i], 0, wxEXPAND | (wxLEFT | wxRIGHT | wxDOWN), 5);
+ m_SizeParent[i]->Add(m_HorizControllers[i], 0, wxEXPAND | (wxLEFT | wxRIGHT | wxDOWN), 5);
+ m_SizeParent[i]->Add(m_HorizControllerMapping[i], 0, wxEXPAND | (wxLEFT | wxRIGHT | wxDOWN), 5);
+
+ // The sizer m_sMain will be expanded inside m_Controller, m_SizeParent will not
+ m_sMain[i] = new wxBoxSizer(wxVERTICAL);
+ m_sMain[i]->Add(m_SizeParent[i]);
+
+ // Set the main sizer
+ m_Controller[i]->SetSizer(m_sMain[i]);
+ /////////////////////////////////
+
+ // Update with the progress (i) and the message
+ dialog.Update(i + 1, wxT("Loading notebook pages..."));
+ }
+
+ ////////////////////////////////////////////
+ // Movement recording
+ // ----------------
+ CreateGUIControlsRecording();
+ /////////////////////////////////
+
+ // Update with the progress (i) and the message (msg)
+ dialog.Update(5, wxT("Loading notebook pages..."));
+ //dialog.Close();
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Buttons
+ //m_About = new wxButton(this, ID_ABOUTOGL, wxT("About"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator);
+ m_Apply = new wxButton(this, ID_APPLY, wxT("Apply"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator);
+ m_Close = new wxButton(this, ID_CLOSE, wxT("Close"));
+ m_Close->SetToolTip(wxT("Apply and Close"));
+
+ wxBoxSizer* sButtons = new wxBoxSizer(wxHORIZONTAL);
+ //sButtons->Add(m_About, 0, wxALL, 5); // there is no about
+ sButtons->AddStretchSpacer();
+ sButtons->Add(m_Apply, 0, (wxALL), 0);
+ sButtons->Add(m_Close, 0, (wxLEFT), 5);
+ ///////////////////////////////
+
+
+ ////////////////////////////////////////////
+ // Set sizers and layout
+ // ----------------
+ m_MainSizer = new wxBoxSizer(wxVERTICAL);
+ m_MainSizer->Add(m_Notebook, 1, wxEXPAND | wxALL, 5);
+ m_MainSizer->Add(sButtons, 0, wxEXPAND | (wxLEFT | wxRIGHT | wxDOWN), 5);
+
+ for (int i = MAX_WIIMOTES - 1; i > 0; i--)
+ {
+ m_Controller[i]->Enable(false);
+ }
+
+ this->SetSizer(m_MainSizer);
+ this->Layout();
+
+ Fit();
+
+ // Center the window if there is room for it
+ #ifdef _WIN32
+ if (GetSystemMetrics(SM_CYFULLSCREEN) > 800)
+ Center();
+ #endif
+
+ ControlsCreated = true;
+ /////////////////////////////////
+}
+/////////////////////////////////
+
+
+
+// ===================================================
+/* Do connect real wiimote */
+// ----------------
+void ConfigDialog::DoConnectReal()
+{
+ g_Config.bConnectRealWiimote = m_ConnectRealWiimote[Page]->IsChecked();
+
+ if(g_Config.bConnectRealWiimote)
+ {
+ if (!g_RealWiiMoteInitialized) WiiMoteReal::Initialize();
+ }
+ else
+ {
+ INFO_LOG(CONSOLE, "Post Message: %i\n", g_RealWiiMoteInitialized);
+ if (g_RealWiiMoteInitialized)
+ {
+ WiiMoteReal::Shutdown();
+ /*
+ if (g_WiimoteUnexpectedDisconnect)
+ {
+ #ifdef _WIN32
+ PostMessage(g_ParentHWND, WM_USER, WIIMOTE_RECONNECT, 0);
+ g_WiimoteUnexpectedDisconnect = false;
+ #endif
+ }
+ */
+ }
+ }
+}
+
+
+// ===================================================
+/* Do use real wiimote. We let the game set up the real Wiimote reporting mode and init the Extension when we change
+ want to use it again. */
+// ----------------
+void ConfigDialog::DoUseReal()
+{
+ // Clear any eventual events in the Wiimote queue
+ WiiMoteReal::ClearEvents();
+
+ // Are we using an extension now? The report that it's removed, then reconnected.
+ bool UsingExtension = false;
+ if (g_Config.bNunchuckConnected || g_Config.bClassicControllerConnected)
+ UsingExtension = true;
+
+ INFO_LOG(CONSOLE, "\nDoUseReal() Connect extension: %i\n", !UsingExtension);
+ DoExtensionConnectedDisconnected(UsingExtension ? 0 : 1);
+
+ UsingExtension = !UsingExtension;
+ INFO_LOG(CONSOLE, "\nDoUseReal() Connect extension: %i\n", !UsingExtension);
+ DoExtensionConnectedDisconnected(UsingExtension ? 1 : 0);
+
+ if(g_EmulatorRunning)
+ {
+ // Disable the checkbox for a moment
+ SetCursor(wxCursor(wxCURSOR_WAIT));
+ m_bEnableUseRealWiimote = false;
+ // We may not need this if there is already a message queue that allows the nessesary timeout
+ //sleep(100);
+
+ /* Start the timer to allow the approximate time it takes for the Wiimote to come online
+ it would simpler to use sleep(1000) but that doesn't work because we need the functions in main.cpp
+ to work */
+ m_TimeoutOnce->Start(1000, true);
+ }
+}
+
+// ===================================================
+/* Generate connect/disconnect status event */
+// ----------------
+void ConfigDialog::DoExtensionConnectedDisconnected(int Extension)
+{
+ // There is no need for this if no game is running
+ if(!g_EmulatorRunning) return;
+
+ u8 DataFrame[8]; // make a blank report for it
+ wm_request_status *rs = (wm_request_status*)DataFrame;
+
+ // Check if a game is running, in that case change the status
+ if(WiiMoteEmu::g_ReportingChannel > 0)
+ WiiMoteEmu::WmRequestStatus(WiiMoteEmu::g_ReportingChannel, rs, Extension);
+}
+
+// ===================================================
+/* Change settings */
+// ----------------
+void ConfigDialog::GeneralSettingsChanged(wxCommandEvent& event)
+{
+ long TmpValue;
+
+ switch (event.GetId())
+ {
+ case ID_CONNECT_REAL:
+ DoConnectReal();
+ break;
+ case ID_USE_REAL:
+ // Enable the Wiimote thread
+ g_Config.bUseRealWiimote = m_UseRealWiimote[Page]->IsChecked();
+ if(g_Config.bUseRealWiimote) DoUseReal();
+ break;
+
+ case ID_SIDEWAYSDPAD:
+ g_Config.bSidewaysDPad = m_SidewaysDPad[Page]->IsChecked();
+ break;
+
+ //////////////////////////
+ // Extensions
+ // -----------
+ case ID_NUNCHUCKCONNECTED:
+ // Don't allow two extensions at the same time
+ if(m_ClassicControllerConnected[Page]->IsChecked())
+ {
+ m_ClassicControllerConnected[Page]->SetValue(false);
+ g_Config.bClassicControllerConnected = false;
+ // Disconnect the extension so that the game recognize the change
+ DoExtensionConnectedDisconnected();
+ /* It doesn't seem to be needed but shouldn't it at least take 25 ms to
+ reconnect an extension after we disconnected another? */
+ if(g_EmulatorRunning) sleep(25);
+ }
+
+ // Update status
+ g_Config.bNunchuckConnected = m_NunchuckConnected[Page]->IsChecked();
+
+ // Copy the calibration data
+ WiiMoteEmu::SetDefaultExtensionRegistry();
+
+ // Generate connect/disconnect status event
+ DoExtensionConnectedDisconnected();
+ break;
+
+ case ID_CLASSICCONTROLLERCONNECTED:
+ // Don't allow two extensions at the same time
+ if(m_NunchuckConnected[Page]->IsChecked())
+ {
+ m_NunchuckConnected[Page]->SetValue(false);
+ g_Config.bNunchuckConnected = false;
+ // Disconnect the extension so that the game recognize the change
+ DoExtensionConnectedDisconnected();
+ }
+ g_Config.bClassicControllerConnected = m_ClassicControllerConnected[Page]->IsChecked();
+
+ // Copy the calibration data
+ WiiMoteEmu::SetDefaultExtensionRegistry();
+ // Generate connect/disconnect status event
+ DoExtensionConnectedDisconnected();
+ break;
+
+ //////////////////////////
+ // Gamepad
+ // -----------
+ case ID_TRIGGER_TYPE:
+ WiiMoteEmu::PadMapping[Page].triggertype = m_TriggerType[Page]->GetSelection();
+ break;
+ case ID_TILT_INPUT:
+ g_Config.Trigger.Type = m_TiltComboInput[Page]->GetSelection();
+ break;
+ case ID_TILT_RANGE_ROLL:
+ m_TiltComboRangeRoll[Page]->GetValue().ToLong(&TmpValue); g_Config.Trigger.Range.Roll = TmpValue;
+ break;
+ case ID_TILT_RANGE_PITCH:
+ m_TiltComboRangePitch[Page]->GetValue().ToLong(&TmpValue); g_Config.Trigger.Range.Pitch = TmpValue;
+ break;
+ case IDC_JOYNAME:
+ DoChangeJoystick();
+ break;
+ case IDCB_NUNCHUCK_STICK:
+ g_Config.Nunchuck.Type = m_NunchuckComboStick[Page]->GetSelection();
+ break;
+ case IDCB_CC_LEFT_STICK:
+ g_Config.ClassicController.LType = m_CcComboLeftStick[Page]->GetSelection();
+ break;
+ case IDCB_CC_RIGHT_STICK:
+ g_Config.ClassicController.RType = m_CcComboRightStick[Page]->GetSelection();
+ break;
+ case IDCB_CC_TRIGGERS:
+ g_Config.ClassicController.TType = m_CcComboTriggers[Page]->GetSelection();
+ break;
+
+ // These are defined in PadMapping and we can run the same function to update all of them
+ case IDCB_LEFT_DIAGONAL:
+ case IDC_LEFT_C2S:
+ case ID_TILT_INVERT_ROLL:
+ case ID_TILT_INVERT_PITCH:
+ SaveButtonMappingAll(Page);
+ break;
+ case IDCB_DEAD_ZONE_LEFT:
+ SaveButtonMappingAll(Page);
+ break;
+ case IDCB_DEAD_ZONE_RIGHT:
+ SaveButtonMappingAll(Page);
+ break;
+
+ //////////////////////////
+ // Recording
+ // -----------
+ case ID_UPDATE_REAL:
+ g_Config.bUpdateRealWiimote = m_UpdateMeters->IsChecked();
+ break;
+
+ case IDC_RECORD + 1:
+ case IDC_RECORD + 2:
+ case IDC_RECORD + 3:
+ case IDC_RECORD + 4:
+ case IDC_RECORD + 5:
+ case IDC_RECORD + 6:
+ case IDC_RECORD + 7:
+ case IDC_RECORD + 8:
+ case IDC_RECORD + 9:
+ case IDC_RECORD + 10:
+ case IDC_RECORD + 11:
+ case IDC_RECORD + 12:
+ case IDC_RECORD + 13:
+ case IDC_RECORD + 14:
+ case IDC_RECORD + 15:
+ // Check if any of the other choice boxes has the same hotkey
+ for (int i = 1; i < (RECORDING_ROWS + 1); i++)
+ {
+ int CurrentChoiceBox = (event.GetId() - IDC_RECORD);
+ if (i == CurrentChoiceBox) continue;
+ if (m_RecordHotKeyWiimote[i]->GetSelection() == m_RecordHotKeyWiimote[CurrentChoiceBox]->GetSelection()) m_RecordHotKeyWiimote[i]->SetSelection(10);
+ if (m_RecordHotKeyNunchuck[i]->GetSelection() == m_RecordHotKeyNunchuck[CurrentChoiceBox]->GetSelection()) m_RecordHotKeyNunchuck[i]->SetSelection(10);
+ if (m_RecordHotKeyIR[i]->GetSelection() == m_RecordHotKeyIR[CurrentChoiceBox]->GetSelection()) m_RecordHotKeyIR[i]->SetSelection(10);
+
+ //INFO_LOG(CONSOLE, "HotKey: %i %i\n",
+ // m_RecordHotKey[i]->GetSelection(), m_RecordHotKey[CurrentChoiceBox]->GetSelection());
+ }
+ break;
+ /////////////////
+ }
+ g_Config.Save();
+ UpdateGUI();
+}
+
+// =======================================================
+// Apparently we need a scroll event version of this for the sliders
+// -------------
+void ConfigDialog::GeneralSettingsChangedScroll(wxScrollEvent& event)
+{
+ switch (event.GetId())
+ {
+ // IR cursor position
+ case IDS_WIDTH:
+ g_Config.iIRWidth = m_SliderWidth[Page]->GetValue();
+ break;
+ case IDS_HEIGHT:
+ g_Config.iIRHeight = m_SliderHeight[Page]->GetValue();
+ break;
+ case IDS_LEFT:
+ g_Config.iIRLeft = m_SliderLeft[Page]->GetValue();
+ break;
+ case IDS_TOP:
+ g_Config.iIRTop = m_SliderTop[Page]->GetValue();
+ break;
+ }
+
+ UpdateGUI();
+}
+
+// =======================================================
+// Update the IR pointer calibration sliders
+// -------------
+void ConfigDialog::UpdateControls()
+{
+ // Update the slider position if a configuration has been loaded
+ m_SliderWidth[Page]->SetValue(g_Config.iIRWidth);
+ m_SliderHeight[Page]->SetValue(g_Config.iIRHeight);
+ m_SliderLeft[Page]->SetValue(g_Config.iIRLeft);
+ m_SliderTop[Page]->SetValue(g_Config.iIRTop);
+
+ // Update the labels
+ m_TextScreenWidth[Page]->SetLabel(wxString::Format(wxT("Width: %i"), g_Config.iIRWidth));
+ m_TextScreenHeight[Page]->SetLabel(wxString::Format(wxT("Height: %i"), g_Config.iIRHeight));
+ m_TextScreenLeft[Page]->SetLabel(wxString::Format(wxT("Left: %i"), g_Config.iIRLeft));
+ m_TextScreenTop[Page]->SetLabel(wxString::Format(wxT("Top: %i"), g_Config.iIRTop));
+}
+// ==============================
+
+
+// =======================================================
+// Update the enabled/disabled status
+// -------------
+void ConfigDialog::UpdateGUI(int Slot)
+{
+ //INFO_LOG(CONSOLE, "UpdateGUI: \n");
+
+ // Update the gamepad settings
+ UpdateGUIButtonMapping(Page);
+
+ // Update dead zone
+ DoChangeDeadZone(true); DoChangeDeadZone(false);
+
+ // Update the Wiimote IR pointer calibration
+ UpdateControls();
+
+ /* We only allow a change of extension if we are not currently using the real Wiimote, if it's in use the status will be updated
+ from the data scanning functions in main.cpp */
+ bool AllowExtensionChange = !(g_RealWiiMotePresent && g_Config.bConnectRealWiimote && g_Config.bUseRealWiimote && g_EmulatorRunning);
+ m_NunchuckConnected[Page]->SetValue(g_Config.bNunchuckConnected);
+ m_ClassicControllerConnected[Page]->SetValue(g_Config.bClassicControllerConnected);
+ m_NunchuckConnected[Page]->Enable(AllowExtensionChange);
+ m_ClassicControllerConnected[Page]->Enable(AllowExtensionChange);
+
+ /* I have disabled this option during a running game because it's enough to be able to switch
+ between using and not using then. To also use the connect option during a running game would
+ mean that the wiimote must be sent the current reporting mode and the channel ID after it
+ has been initialized. Functions for that are basically already in place so these two options
+ could possibly be simplified to one option. */
+ m_ConnectRealWiimote[Page]->Enable(!g_EmulatorRunning);
+ m_UseRealWiimote[Page]->Enable((m_bEnableUseRealWiimote && g_RealWiiMotePresent && g_Config.bConnectRealWiimote) || (!g_EmulatorRunning && g_Config.bConnectRealWiimote));
+
+ // Linux has no FindItem()
+ // Disable all pad items if no pads are detected
+ if(ControlsCreated)
+ {
+ bool PadEnabled = WiiMoteEmu::NumGoodPads != 0;
+ #ifdef _WIN32
+ for(int i = IDB_ANALOG_LEFT_X; i <= IDB_TRIGGER_R; i++) m_Notebook->FindItem(i)->Enable(PadEnabled);
+ m_Notebook->FindItem(IDC_JOYNAME)->Enable(PadEnabled);
+ m_Notebook->FindItem(IDC_LEFT_C2S)->Enable(PadEnabled);
+ m_Notebook->FindItem(IDCB_LEFT_DIAGONAL)->Enable(PadEnabled);
+ m_Notebook->FindItem(IDCB_DEAD_ZONE_LEFT)->Enable(PadEnabled);
+ m_Notebook->FindItem(IDCB_DEAD_ZONE_RIGHT)->Enable(PadEnabled);
+ m_Notebook->FindItem(ID_TRIGGER_TYPE)->Enable(PadEnabled);
+ #endif
+ }
+
+ // Disable all recording buttons
+ bool ActiveRecording = !(m_bWaitForRecording || m_bRecording);
+ #ifdef _WIN32
+ for(int i = IDB_RECORD + 1; i < (IDB_RECORD + RECORDING_ROWS + 1); i++)
+ if(ControlsCreated) m_Notebook->FindItem(i)->Enable(ActiveRecording);
+ #endif
+}
+
diff --git a/Source/Plugins/Plugin_Wiimote-testing/Src/ConfigDlg.h b/Source/Plugins/Plugin_Wiimote-testing/Src/ConfigDlg.h
new file mode 100644
index 0000000000..6aa18d1bb7
--- /dev/null
+++ b/Source/Plugins/Plugin_Wiimote-testing/Src/ConfigDlg.h
@@ -0,0 +1,275 @@
+// Copyright (C) 2003-2008 Dolphin Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official SVN repository and contact information can be found at
+// http://code.google.com/p/dolphin-emu/
+
+#ifndef __CONFIGDIALOG_h__
+#define __CONFIGDIALOG_h__
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+class ConfigDialog : public wxDialog
+{
+ public:
+ ConfigDialog(wxWindow *parent, wxWindowID id = 1,
+ const wxString &title = wxT("Wii Remote Plugin Configuration"),
+ const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
+ long style = wxDEFAULT_DIALOG_STYLE | wxWANTS_CHARS);
+ virtual ~ConfigDialog();
+
+ // General open, close and event functions
+ void CloseClick(wxCommandEvent& event);
+ void UpdateGUI(int Slot = 0); void UpdateGUIButtonMapping(int controller); void UpdateControls();
+ void OnKeyDown(wxKeyEvent& event);
+ void LoadFile(); void SaveFile();
+
+ // Timers
+ wxTimer *m_TimeoutTimer, *m_ShutDownTimer, *m_TimeoutOnce, *m_ButtonMappingTimer, *m_UpdatePad;
+
+ // General status
+ wxStaticText * m_TextUpdateRate;
+
+ // Wiimote status
+ wxGauge *m_GaugeBattery, *m_GaugeRoll[2], *m_GaugeGForce[3], *m_GaugeAccel[3];
+ wxStaticBitmap *m_bmpDotLeftIn[4], *m_bmpDotLeftOut[4], *m_bmpDotRightIn[4], *m_bmpDotRightOut[4],
+ *m_bmpDeadZoneLeftIn[4], *m_bmpDeadZoneRightIn[4];
+ wxStaticText *m_TextIR;
+ bool m_bWaitForRecording, m_bRecording, m_bAllowA;
+ int m_iRecordTo;
+ void RecordMovement(wxCommandEvent& event);
+ void DoRecordMovement(int _x, int _y, int _z, const u8 *_IR, int IRBytes);
+ void DoRecordA(bool Pressed);
+ void Convert2Box(int &x);
+ void ConvertToString();
+ void Update(wxTimerEvent& WXUNUSED(event));
+ void ShutDown(wxTimerEvent& WXUNUSED(event));
+ void UpdateOnce(wxTimerEvent& event);
+
+ // Gamepad configuration
+ void OnButtonTimer(wxTimerEvent& WXUNUSED(event)) { DoGetButtons(GetButtonWaitingID); }
+ void UpdatePad(wxTimerEvent& WXUNUSED(event));
+
+ private:
+ DECLARE_EVENT_TABLE();
+
+ bool ControlsCreated, m_bEnableUseRealWiimote; int Page, BoxW, BoxH, g_Pressed;
+
+ wxNotebook *m_Notebook;
+ wxPanel *m_Controller[4], *m_PageRecording;
+ wxButton *m_About, *m_Close, *m_Apply;
+ wxBoxSizer *m_MainSizer, *m_sMain[4], *m_SizeParent[4], *m_sRecordingMain;
+
+ // Emulated Wiimote key settings
+ wxBoxSizer *m_SizerIRPointerWidth[4], *m_SizerIRPointerHeight[4], *m_SizerIRPointerScreen[4],
+ *m_SizeBasicPadding[4], *m_SizeEmuPadding[4], *m_SizeRealPadding[4], *m_SizeExtensionsPadding[4],
+ *m_SizeBasicGeneral[4], *m_SizeBasicGeneralLeft[4], *m_SizeBasicGeneralRight[4],
+ *m_HorizControllers[4], *m_gC2SDeadZone[4], *m_gCircle2Square[4], *m_gCircle2SquareVert[4], *m_gDeadZone[4], *m_gDeadZoneHoriz[4], *m_HorizControllerTiltParent[4], *m_HorizControllerTilt[4], *m_TiltHoriz[4],
+ *m_SizeAnalogLeft[4], *m_SizeAnalogLeftHorizX[4], *m_SizeAnalogLeftHorizY[4], *m_SizeAnalogRight[4], *m_SizeAnalogRightHorizX[4], *m_SizeAnalogRightHorizY[4],
+ *m_SizeAnalogTriggerVertLeft[4], *m_SizeAnalogTriggerVertRight[4], *m_SizeAnalogTriggerHorizInput[4],
+ // Nunchuck
+ *m_SNcShake[4], *m_SNcZ[4], *m_SNcC[4], *m_SNcL[4], *m_SNcR[4], *m_SNcU[4], *m_SNcD[4],
+ // Wiimote
+ *m_SWmVertLeft[4], *m_SWmVertRight[4], *m_SWmShake[4], *m_SWmPitchL[4], *m_SWmPitchR[4], *m_SWmA[4], *m_SWmB[4], *m_SWm1[4], *m_SWm2[4], *m_SWmP[4], *m_SWmM[4], *m_SWmH[4], *m_SWmL[4], *m_SWmR[4], *m_SWmU[4], *m_SWmD[4],
+ *m_HorizControllerMapping[4], *m_NunchuckStick[4],
+ // Classic Controller
+ *m_SCcVertLeft[4], *m_SCcVertMiddle[4], *m_SCcVertRight[4],
+ *m_SCcLeftStick[4], *m_SCcRightStick[4], *m_SCcTriggers[4],
+ *m_SCcA[4], *m_SCcB[4], *m_SCcX[4], *m_SCcY[4],
+ *m_SCcP[4], *m_SCcM[4], *m_SCcH[4],
+ *m_SCcTl[4], *m_SCcZl[4], *m_SCcZr[4], *m_SCcTr[4],
+ *m_SCcDl[4], *m_SCcDu[4], *m_SCcDr[4], *m_SCcDd[4],
+ *m_SCcLl[4], *m_SCcLu[4], *m_SCcLr[4], *m_SCcLd[4],
+ *m_SCcRl[4], *m_SCcRu[4], *m_SCcRr[4], *m_SCcRd[4];
+ wxGridBagSizer *m_SizeAnalogTriggerHorizConfig[4], *m_SizeAnalogTriggerStatusBox[4], *m_TiltGrid[4],
+ *m_GridLeftStick[4], *m_GridRightStick[4];
+ wxStaticBoxSizer *m_SizeBasic[4], *m_SizeEmu[4], *m_SizeReal[4], *m_SizeExtensions[4], *m_SizerIRPointer[4], *m_gTilt[4], *m_gJoyname[4];
+ wxTextCtrl *m_AnalogLeftX[4], *m_AnalogLeftY[4], *m_AnalogRightX[4], *m_AnalogRightY[4],
+ *m_AnalogTriggerL[4], *m_AnalogTriggerR[4];
+ wxButton *m_bAnalogLeftX[4], *m_bAnalogLeftY[4], *m_bAnalogRightX[4], *m_bAnalogRightY[4],
+ *m_bAnalogTriggerL[4], *m_bAnalogTriggerR[4],
+ // Nunchuck
+ *m_bNcShake[4], *m_bNcZ[4], *m_bNcC[4], *m_bNcL[4], *m_bNcR[4], *m_bNcU[4], *m_bNcD[4],
+ // Wiimote
+ *m_bWmShake[4], *m_bWmPitchL[4], *m_bWmPitchR[4], *m_bWmA[4], *m_bWmB[4], *m_bWm1[4], *m_bWm2[4], *m_bWmP[4], *m_bWmM[4], *m_bWmH[4], *m_bWmD[4], *m_bWmU[4], *m_bWmR[4], *m_bWmL[4],
+ // Classic Controller
+ *m_bCcA[4], *m_bCcB[4], *m_bCcX[4], *m_bCcY[4],
+ *m_bCcP[4], *m_bCcM[4], *m_bCcH[4],
+ *m_bCcTl[4], *m_bCcZl[4], *m_bCcZr[4], *m_bCcTr[4],
+ *m_bCcDl[4], *m_bCcDu[4], *m_bCcDr[4], *m_bCcDd[4],
+ *m_bCcLl[4], *m_bCcLu[4], *m_bCcLr[4], *m_bCcLd[4],
+ *m_bCcRl[4], *m_bCcRu[4], *m_bCcRr[4], *m_bCcRd[4];
+ wxStaticText *m_TextScreenWidth[4], *m_TextScreenHeight[4], *m_TextScreenLeft[4], *m_TextScreenTop[4], *m_TextAR[4],
+ *m_tAnalogX[8], *m_tAnalogY[8], *m_TiltTextRoll[4], *m_TiltTextPitch[4],
+ *m_CheckC2SLabel[4], *m_ComboDeadZoneLabel[4], *m_TStatusLeftIn[4], *m_TStatusLeftOut[4], *m_TStatusRightIn[4], *m_TStatusRightOut[4],
+ *m_TriggerStatusL[4], *m_TriggerStatusR[4], *m_TriggerStatusLx[4], *m_TriggerStatusRx[4],
+ *m_tAnalogTriggerInput[4], *m_tAnalogTriggerL[4], *m_tAnalogTriggerR[4],
+ // Nunchuck
+ *m_tNcShake[4], *m_tNcZ[4], *m_tNcC[4], *m_tNcL[4], *m_tNcR[4], *m_tNcU[4], *m_tNcD[4],
+ // Wiimote
+ *m_tWmShake[4], *m_tWmPitchL[4], *m_tWmPitchR[4], *m_tWmA[4], *m_tWmB[4], *m_tWm1[4], *m_tWm2[4], *m_tWmP[4], *m_tWmM[4], *m_tWmH[4], *m_tWmL[4], *m_tWmR[4], *m_tWmU[4],*m_tWmD[4],
+ *m_NunchuckTextStick[5],
+ // Classic Controller
+ *m_tCcA[4], *m_tCcB[4], *m_tCcX[4], *m_tCcY[4],
+ *m_tCcP[4], *m_tCcM[4], *m_tCcH[4],
+ *m_tCcTl[4], *m_tCcZl[4], *m_tCcZr[4], *m_tCcTr[4],
+ *m_tCcDl[4], *m_tCcDu[4], *m_tCcDr[4], *m_tCcDd[4],
+ *m_tCcLl[4], *m_tCcLu[4], *m_tCcLr[4], *m_tCcLd[4],
+ *m_tCcRl[4], *m_tCcRu[4], *m_tCcRr[4], *m_tCcRd[4],
+ *m_CcTextLeftStick[4], *m_CcTextRightStick[4], *m_CcTextTriggers[4];
+ wxButton *ClickedButton;
+ wxString OldLabel;
+ wxSlider *m_SliderWidth[4], *m_SliderHeight[4], *m_SliderLeft[4], *m_SliderTop[4];
+
+ // Emulated Wiimote settings
+ wxCheckBox *m_SidewaysDPad[4], *m_WiimoteOnline[4],
+ *m_CheckC2S[4], *m_TiltInvertRoll[4], *m_TiltInvertPitch[4],
+ *m_WiiMotionPlusConnected[4], *m_NunchuckConnected[4], *m_ClassicControllerConnected[4], *m_BalanceBoardConnected[4], *m_GuitarHeroGuitarConnected[4], *m_GuitarHeroWorldTourDrumsConnected[4],
+ *m_CheckAR43[4], *m_CheckAR169[4], *m_Crop[4];
+ wxComboBox *m_TiltComboInput[4], *m_TiltComboRangeRoll[4], *m_TiltComboRangePitch[4], *m_Joyname[4], *m_ComboDiagonal[4], *m_ComboDeadZoneLeft[4], *m_ComboDeadZoneRight[4], *m_TriggerType[4],
+ *m_NunchuckComboStick[4], *m_CcComboLeftStick[4], *m_CcComboRightStick[4], *m_CcComboTriggers[4];
+
+ // Real Wiimote settings
+ wxCheckBox *m_ConnectRealWiimote[4], *m_UseRealWiimote[4], *m_UpdateMeters;
+
+ wxPanel *m_pLeftInStatus[4], *m_pLeftOutStatus[4], *m_pRightInStatus[4], *m_pRightOutStatus[4];
+ wxStaticBitmap *m_bmpSquareLeftIn[4], *m_bmpSquareLeftOut[4], *m_bmpSquareRightIn[4], *m_bmpSquareRightOut[4];
+ wxStaticBoxSizer *m_gAnalogLeft[4], *m_gAnalogRight[4], *m_gTrigger[4],
+ *m_gWiimote[4], *m_gNunchuck[4], *m_gClassicController[4];
+ wxBitmap CreateBitmapDot(), CreateBitmap(), CreateBitmapDeadZone(int Radius), CreateBitmapClear();
+
+ wxButton * m_RecordButton[RECORDING_ROWS + 1];
+ wxChoice * m_RecordHotKeySwitch[RECORDING_ROWS + 1];
+ wxChoice * m_RecordHotKeyWiimote[RECORDING_ROWS + 1];
+ wxChoice * m_RecordHotKeyNunchuck[RECORDING_ROWS + 1];
+ wxChoice * m_RecordHotKeyIR[RECORDING_ROWS + 1];
+ wxTextCtrl * m_RecordText[RECORDING_ROWS + 1];
+ wxTextCtrl * m_RecordGameText[RECORDING_ROWS + 1];
+ wxTextCtrl * m_RecordIRBytesText[RECORDING_ROWS + 1];
+ wxTextCtrl * m_RecordSpeed[RECORDING_ROWS + 1];
+ wxChoice * m_RecordPlayBackSpeed[RECORDING_ROWS + 1];
+
+ /*
+ struct m_sRecording
+ {
+ u8 x;
+ u8 y;
+ u8 z;
+ double Time;
+ };
+ */
+ std::vector m_vRecording;
+ int IRBytes;
+
+ enum
+ {
+ ID_CLOSE = 1000,
+ ID_APPLY,
+ ID_ABOUTOGL,
+ IDTM_EXIT, IDTM_UPDATE, IDTM_SHUTDOWN, IDTM_UPDATE_ONCE, IDTM_BUTTON, IDTM_UPDATE_PAD, // Timer
+
+ ID_NOTEBOOK, ID_CONTROLLERPAGE1, ID_CONTROLLERPAGE2, ID_CONTROLLERPAGE3, ID_CONTROLLERPAGE4, ID_PAGE_RECORDING,
+
+ // Emulated Wiimote
+ ID_SIDEWAYSDPAD,
+ ID_NUNCHUCKCONNECTED, ID_CLASSICCONTROLLERCONNECTED,
+ IDC_WIMOTE_ON,
+
+ // Gamepad
+ IDB_ANALOG_LEFT_X, IDB_ANALOG_LEFT_Y,
+ IDB_ANALOG_RIGHT_X, IDB_ANALOG_RIGHT_Y,
+ IDB_TRIGGER_L, IDB_TRIGGER_R,
+
+ ID_ANALOG_LEFT_X, ID_ANALOG_LEFT_Y,
+ ID_ANALOG_RIGHT_X, ID_ANALOG_RIGHT_Y,
+ ID_TRIGGER_L, ID_TRIGGER_R,
+
+ // Wiimote
+ IDS_WIDTH, IDS_HEIGHT, IDS_LEFT, IDS_TOP,
+ IDB_WM_A, IDB_WM_B,
+ IDB_WM_1, IDB_WM_2,
+ IDB_WM_P, IDB_WM_M, IDB_WM_H,
+ IDB_WM_L, IDB_WM_R, IDB_WM_U, IDB_WM_D,
+ IDB_WM_SHAKE, IDB_WM_PITCH_L, IDB_WM_PITCH_R,
+
+ // Nunchuck
+ IDB_NC_Z, IDB_NC_C, IDB_NC_L, IDB_NC_R, IDB_NC_U, IDB_NC_D,
+ IDB_NC_SHAKE,
+
+ // Classic Controller
+ IDB_CC_A, IDB_CC_B,
+ IDB_CC_X, IDB_CC_Y,
+ IDB_CC_P, IDB_CC_M, IDB_CC_H,
+ IDB_CC_TL, IDB_CC_ZL, IDB_CC_ZR, IDB_CC_TR,
+ IDB_CC_DL, IDB_CC_DU, IDB_CC_DR, IDB_CC_DD, // Digital pad
+ IDB_CC_LL, IDB_CC_LU, IDB_CC_LR, IDB_CC_LD, // Left analog stick
+ IDB_CC_RL, IDB_CC_RU, IDB_CC_RR, IDB_CC_RD, // Right analog stick
+
+ // Gamepad settings
+ IDC_JOYNAME, IDC_LEFT_C2S, IDCB_LEFT_DIAGONAL, IDCB_DEAD_ZONE_LEFT, IDCB_DEAD_ZONE_RIGHT,
+ ID_TRIGGER_TYPE, ID_TILT_INPUT, ID_TILT_RANGE_ROLL, ID_TILT_RANGE_PITCH, ID_TILT_INVERT_ROLL, ID_TILT_INVERT_PITCH,
+ IDCB_NUNCHUCK_STICK, IDCB_CC_LEFT_STICK, IDCB_CC_RIGHT_STICK, IDCB_CC_TRIGGERS,
+
+ // Real
+ ID_CONNECT_REAL, ID_USE_REAL, ID_UPDATE_REAL, IDT_STATUS,
+ IDB_RECORD = 2000,
+ IDC_RECORD = 3000,
+ IDC_PLAY_WIIMOTE, IDC_PLAY_NUNCHUCK, IDC_PLAY_IR, IDT_RECORD_TEXT, IDT_RECORD_GAMETEXT, IDT_RECORD_IRBYTESTEXT, IDT_RECORD_SPEED, IDT_RECORD_PLAYSPEED
+ };
+
+ void OnClose(wxCloseEvent& event);
+ void CreateGUIControls();
+ void CreateGUIControlsRecording();
+ void AboutClick(wxCommandEvent& event);
+ void GeneralSettingsChanged(wxCommandEvent& event);
+ void GeneralSettingsChangedScroll(wxScrollEvent& event);
+
+ void DoConnectReal(); // Real
+ void DoUseReal();
+
+ void DoExtensionConnectedDisconnected(int Extension = -1); // Emulated
+
+ // Gamepad configuration
+ void SetButtonText(int id, char text[128], int _Page = -1); void SetButtonTextAll(int id, char text[128]);
+ wxString GetButtonText(int id, int Page = -1);
+ void GetButtons(wxCommandEvent& event); void DoGetButtons(int);
+ void SaveButtonMapping(int controller, bool DontChangeId = false, int FromSlot = -1); void SaveButtonMappingAll(int Slot);
+ void SaveKeyboardMapping(int Controller, int Id, int Key);
+ void ToBlank(bool ToBlank = true);
+ void PadGetStatus();
+ void DoSave(bool ChangePad = false, int Slot = -1);
+ void DoChangeJoystick(); void PadOpen(int Open); void PadClose(int Close); void DoChangeDeadZone(bool Left);
+ void OnButtonClick(wxCommandEvent& event);
+
+ // Configure buttons
+ int GetButtonWaitingID, GetButtonWaitingTimer;
+};
+
+extern ConfigDialog *frame;
+
+#endif
\ No newline at end of file
diff --git a/Source/Plugins/Plugin_Wiimote-testing/Src/ConfigGamepad.cpp b/Source/Plugins/Plugin_Wiimote-testing/Src/ConfigGamepad.cpp
new file mode 100644
index 0000000000..22a2642ba6
--- /dev/null
+++ b/Source/Plugins/Plugin_Wiimote-testing/Src/ConfigGamepad.cpp
@@ -0,0 +1,838 @@
+// Copyright (C) 2003-2008 Dolphin Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official SVN repository and contact information can be found at
+// http://code.google.com/p/dolphin-emu/
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Includes
+// ŻŻŻŻŻŻŻŻŻŻŻŻŻ
+//#include "Common.h" // for u16
+#include "CommonTypes.h" // for u16
+#include "IniFile.h"
+#include "Timer.h"
+
+#include "wiimote_real.h" // Local
+#include "wiimote_hid.h"
+#include "main.h"
+#include "ConfigDlg.h"
+#include "Config.h"
+#include "EmuMain.h" // for LoadRecordedMovements()
+#include "EmuSubroutines.h" // for WmRequestStatus
+#include "EmuDefinitions.h" // for joyinfo
+//////////////////////////////////////
+
+
+///////////////////////////////////////////////////////////////////////////////////
+// Change Joystick
+// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
+/* Function: When changing the joystick we save and load the settings and update the PadMapping
+ and PadState array. PadState[].joy is the gamepad handle that is used to access the pad throughout
+ the plugin. Joyinfo[].joy is only used the first time the pads are checked. */
+void ConfigDialog::DoChangeJoystick()
+{
+ // Close the current pad, unless it's used by another slot
+ //if (PadMapping[notebookpage].enabled) PadClose(notebookpage);
+
+ // Before changing the pad we save potential changes to the current pad
+ DoSave(true);
+
+ // Load the settings for the new Id
+ g_Config.Load(true);
+ UpdateGUI(Page); // Update the GUI
+
+ // Open the new pad
+ if (WiiMoteEmu::PadMapping[Page].enabled) PadOpen(Page);
+}
+void ConfigDialog::PadOpen(int Open) // Open for slot 1, 2, 3 or 4
+{
+ // Check that we got a good pad
+ if (!WiiMoteEmu::joyinfo.at(WiiMoteEmu::PadMapping[Open].ID).Good)
+ {
+ INFO_LOG(CONSOLE, "A bad pad was selected\n");
+ WiiMoteEmu::PadState[Open].joy = NULL;
+ return;
+ }
+
+ INFO_LOG(CONSOLE, "Update the Slot %i handle to Id %i\n", Page, WiiMoteEmu::PadMapping[Open].ID);
+ WiiMoteEmu::PadState[Open].joy = SDL_JoystickOpen(WiiMoteEmu::PadMapping[Open].ID);
+}
+void ConfigDialog::PadClose(int Close) // Close for slot 1, 2, 3 or 4
+{
+ if (SDL_JoystickOpened(WiiMoteEmu::PadMapping[Close].ID)) SDL_JoystickClose(WiiMoteEmu::PadState[Close].joy);
+ WiiMoteEmu::PadState[Close].joy = NULL;
+}
+
+void ConfigDialog::DoChangeDeadZone(bool Left)
+{
+ if(Left)
+ {
+ float Rad = (float)WiiMoteEmu::PadMapping[Page].DeadZoneL * ((float)BoxW / 100.0) * 0.5;
+ m_bmpDeadZoneLeftIn[Page]->SetBitmap(CreateBitmapClear());
+ m_bmpDeadZoneLeftIn[Page]->SetSize(0, 0);
+ m_bmpDeadZoneLeftIn[Page]->SetBitmap(CreateBitmapDeadZone((int)Rad));
+ m_bmpDeadZoneLeftIn[Page]->SetPosition(wxPoint(BoxW / 2 - (int)Rad, BoxH / 2 - (int)Rad));
+ m_bmpDeadZoneLeftIn[Page]->Refresh();
+ }
+ else
+ {
+ float Rad = (float)WiiMoteEmu::PadMapping[Page].DeadZoneR * ((float)BoxW / 100.0) * 0.5;
+ m_bmpDeadZoneRightIn[Page]->SetBitmap(CreateBitmapClear());
+ m_bmpDeadZoneRightIn[Page]->SetSize(0, 0);
+ m_bmpDeadZoneRightIn[Page]->SetBitmap(CreateBitmapDeadZone((int)Rad));
+ m_bmpDeadZoneRightIn[Page]->SetPosition(wxPoint(BoxW / 2 - (int)Rad, BoxH / 2 - (int)Rad));
+ m_bmpDeadZoneRightIn[Page]->Refresh();
+ }
+}
+//////////////////////////////////////
+
+
+///////////////////////////////////////////////////////////////////////////////////
+// Change settings
+// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
+
+// Set the button text for all four Wiimotes
+void ConfigDialog::SetButtonTextAll(int id, char text[128])
+{
+ for (int i = 0; i < 1; i++)
+ {
+ // Safety check to avoid crash
+ if ((int)WiiMoteEmu::joyinfo.size() > WiiMoteEmu::PadMapping[i].ID)
+ if (WiiMoteEmu::joyinfo[WiiMoteEmu::PadMapping[i].ID].Name == WiiMoteEmu::joyinfo[WiiMoteEmu::PadMapping[Page].ID].Name)
+ SetButtonText(id, text, i);
+ };
+}
+
+
+void ConfigDialog::SaveButtonMappingAll(int Slot)
+{
+ //INFO_LOG(CONSOLE, "SaveButtonMappingAll()\n");
+
+ for (int i = 0; i < 4; i++)
+ {
+ // This can occur when no gamepad is detected
+ if ((int)WiiMoteEmu::joyinfo.size() > WiiMoteEmu::PadMapping[i].ID)
+ if (WiiMoteEmu::joyinfo[WiiMoteEmu::PadMapping[i].ID].Name == WiiMoteEmu::joyinfo[WiiMoteEmu::PadMapping[Slot].ID].Name)
+ SaveButtonMapping(i, false, Slot);
+ }
+}
+
+// Set dialog items from saved values
+// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
+void ConfigDialog::UpdateGUIButtonMapping(int controller)
+{
+ // Temporary storage
+ wxString tmp;
+
+ // Update selected gamepad
+ m_Joyname[controller]->SetSelection(WiiMoteEmu::PadMapping[controller].ID);
+
+ // Update the enabled checkbox
+ //m_Joyattach[controller]->SetValue(PadMapping[controller].enabled == 1 ? true : false);
+
+ tmp << WiiMoteEmu::PadMapping[controller].Axis.Lx; m_AnalogLeftX[controller]->SetValue(tmp); tmp.clear();
+ tmp << WiiMoteEmu::PadMapping[controller].Axis.Ly; m_AnalogLeftY[controller]->SetValue(tmp); tmp.clear();
+ tmp << WiiMoteEmu::PadMapping[controller].Axis.Rx; m_AnalogRightX[controller]->SetValue(tmp); tmp.clear();
+ tmp << WiiMoteEmu::PadMapping[controller].Axis.Ry; m_AnalogRightY[controller]->SetValue(tmp); tmp.clear();
+
+ tmp << WiiMoteEmu::PadMapping[controller].Axis.Tl; m_AnalogTriggerL[controller]->SetValue(tmp); tmp.clear();
+ tmp << WiiMoteEmu::PadMapping[controller].Axis.Tr; m_AnalogTriggerR[controller]->SetValue(tmp); tmp.clear();
+
+ // Update the deadzone and controller type controls
+ m_TriggerType[controller]->SetSelection(WiiMoteEmu::PadMapping[controller].triggertype);
+ m_ComboDeadZoneLeft[controller]->SetSelection(WiiMoteEmu::PadMapping[controller].DeadZoneL);
+ m_ComboDeadZoneRight[controller]->SetSelection(WiiMoteEmu::PadMapping[controller].DeadZoneR);
+ m_ComboDiagonal[controller]->SetValue(wxString::FromAscii(WiiMoteEmu::PadMapping[controller].SDiagonal.c_str()));
+ m_CheckC2S[controller]->SetValue(WiiMoteEmu::PadMapping[controller].bCircle2Square);
+ m_TiltInvertRoll[controller]->SetValue(WiiMoteEmu::PadMapping[controller].bRollInvert);
+ m_TiltInvertPitch[controller]->SetValue(WiiMoteEmu::PadMapping[controller].bPitchInvert);
+
+ // Wiimote
+#ifdef _WIN32
+ m_bWmA[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Wm.A).c_str()));
+ m_bWmB[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Wm.B).c_str()));
+ m_bWm1[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Wm.One).c_str()));
+ m_bWm2[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Wm.Two).c_str()));
+ m_bWmP[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Wm.P).c_str()));
+ m_bWmM[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Wm.M).c_str()));
+ m_bWmH[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Wm.H).c_str()));
+ m_bWmL[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Wm.L).c_str()));
+ m_bWmR[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Wm.R).c_str()));
+ m_bWmU[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Wm.U).c_str()));
+ m_bWmD[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Wm.D).c_str()));
+ m_bWmShake[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Wm.Shake).c_str()));
+ m_bWmPitchL[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Wm.PitchL).c_str()));
+ m_bWmPitchR[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Wm.PitchR).c_str()));
+
+ // Nunchuck
+ m_bNcZ[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Nc.Z).c_str()));
+ m_bNcC[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Nc.C).c_str()));
+ m_bNcL[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Nc.L).c_str()));
+ m_bNcR[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Nc.R).c_str()));
+ m_bNcU[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Nc.U).c_str()));
+ m_bNcD[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Nc.D).c_str()));
+ m_bNcShake[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Nc.Shake).c_str()));
+
+ // Classic Controller
+ m_bCcA[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Cc.A).c_str()));
+ m_bCcB[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Cc.B).c_str()));
+ m_bCcX[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Cc.X).c_str()));
+ m_bCcY[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Cc.Y).c_str()));
+ m_bCcP[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Cc.P).c_str()));
+ m_bCcM[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Cc.M).c_str()));
+ m_bCcH[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Cc.H).c_str()));
+ m_bCcTl[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Cc.Tl).c_str()));
+ m_bCcZl[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Cc.Zl).c_str()));
+ m_bCcZr[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Cc.Zr).c_str()));
+ m_bCcTr[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Cc.Tr).c_str()));
+ m_bCcDl[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Cc.Dl).c_str()));
+ m_bCcDu[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Cc.Du).c_str()));
+ m_bCcDr[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Cc.Dr).c_str()));
+ m_bCcDd[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Cc.Dd).c_str()));
+ m_bCcLl[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Cc.Ll).c_str()));
+ m_bCcLu[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Cc.Lu).c_str()));
+ m_bCcLr[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Cc.Lr).c_str()));
+ m_bCcLd[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Cc.Ld).c_str()));
+ m_bCcRl[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Cc.Rl).c_str()));
+ m_bCcRu[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Cc.Ru).c_str()));
+ m_bCcRr[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Cc.Rr).c_str()));
+ m_bCcRd[controller]->SetLabel(wxString::FromAscii(InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Cc.Rd).c_str()));
+#endif
+
+ //INFO_LOG(CONSOLE, "m_bWmA[%i] = %i = %s\n", controller, WiiMoteEmu::PadMapping[controller].Wm.A, InputCommon::VKToString(WiiMoteEmu::PadMapping[controller].Wm.A).c_str());
+}
+
+/* Populate the PadMapping array with the dialog items settings (for example
+ selected joystick, enabled or disabled status and so on) */
+// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
+void ConfigDialog::SaveButtonMapping(int controller, bool DontChangeId, int FromSlot)
+{
+ // Temporary storage
+ wxString tmp;
+ long value;
+
+ // Save from or to the same or different slots
+ if (FromSlot == -1) FromSlot = controller;
+
+ // Replace "" with "-1" in the GUI controls
+ ToBlank(false);
+
+ /* Set physical device Id. GetSelection() should never be -1 here so we don't check that it's zero or higher. If it's possible that it can be
+ -1 that's a bug that should be fixed. Because the m_Joyname[] combo box should always show , or a gamepad name, not a
+ a blank selection. */
+ if (!DontChangeId)
+ WiiMoteEmu::PadMapping[controller].ID = m_Joyname[FromSlot]->GetSelection();
+ // Set enabled or disable status
+ if (FromSlot == controller)
+ WiiMoteEmu::PadMapping[controller].enabled = true; //m_Joyattach[FromSlot]->GetValue(); // Only enable one
+ // Set other settings
+ //WiiMoteEmu::PadMapping[controller].controllertype = m_ControlType[FromSlot]->GetSelection();
+ WiiMoteEmu::PadMapping[controller].triggertype = m_TriggerType[FromSlot]->GetSelection();
+ WiiMoteEmu::PadMapping[controller].DeadZoneL = m_ComboDeadZoneLeft[FromSlot]->GetSelection();
+ WiiMoteEmu::PadMapping[controller].DeadZoneR = m_ComboDeadZoneRight[FromSlot]->GetSelection();
+ WiiMoteEmu::PadMapping[controller].SDiagonal = m_ComboDiagonal[FromSlot]->GetLabel().mb_str();
+ WiiMoteEmu::PadMapping[controller].bCircle2Square = m_CheckC2S[FromSlot]->IsChecked();
+ WiiMoteEmu::PadMapping[controller].bRollInvert = m_TiltInvertRoll[FromSlot]->IsChecked();
+ WiiMoteEmu::PadMapping[controller].bPitchInvert = m_TiltInvertPitch[FromSlot]->IsChecked();
+
+ // The analog buttons
+ m_AnalogLeftX[FromSlot]->GetValue().ToLong(&value); WiiMoteEmu::PadMapping[controller].Axis.Lx = value; tmp.clear();
+ m_AnalogLeftY[FromSlot]->GetValue().ToLong(&value); WiiMoteEmu::PadMapping[controller].Axis.Ly = value; tmp.clear();
+ m_AnalogRightX[FromSlot]->GetValue().ToLong(&value); WiiMoteEmu::PadMapping[controller].Axis.Rx = value; tmp.clear();
+ m_AnalogRightY[FromSlot]->GetValue().ToLong(&value); WiiMoteEmu::PadMapping[controller].Axis.Ry = value; tmp.clear();
+
+ // The shoulder buttons
+ m_AnalogTriggerL[FromSlot]->GetValue().ToLong(&value); WiiMoteEmu::PadMapping[controller].Axis.Tl = value;
+ m_AnalogTriggerR[FromSlot]->GetValue().ToLong(&value); WiiMoteEmu::PadMapping[controller].Axis.Tr = value;
+
+ //INFO_LOG(CONSOLE, "WiiMoteEmu::PadMapping[%i].ID = %i, m_Joyname[%i]->GetSelection() = %i\n",
+ // controller, WiiMoteEmu::PadMapping[controller].ID, FromSlot, m_Joyname[FromSlot]->GetSelection());
+
+ // Replace "-1" with ""
+ ToBlank();
+}
+
+// Save keyboard key mapping
+void ConfigDialog::SaveKeyboardMapping(int Controller, int Id, int Key)
+{
+ switch(Id)
+ {
+ // Wiimote
+ case IDB_WM_A: WiiMoteEmu::PadMapping[Controller].Wm.A = Key; break;
+ case IDB_WM_B: WiiMoteEmu::PadMapping[Controller].Wm.B = Key; break;
+ case IDB_WM_1: WiiMoteEmu::PadMapping[Controller].Wm.One = Key; break;
+ case IDB_WM_2: WiiMoteEmu::PadMapping[Controller].Wm.Two = Key; break;
+ case IDB_WM_P: WiiMoteEmu::PadMapping[Controller].Wm.P = Key; break;
+ case IDB_WM_M: WiiMoteEmu::PadMapping[Controller].Wm.M = Key; break;
+ case IDB_WM_H: WiiMoteEmu::PadMapping[Controller].Wm.H = Key; break;
+ case IDB_WM_L: WiiMoteEmu::PadMapping[Controller].Wm.L = Key; break;
+ case IDB_WM_R: WiiMoteEmu::PadMapping[Controller].Wm.R = Key; break;
+ case IDB_WM_U: WiiMoteEmu::PadMapping[Controller].Wm.U = Key; break;
+ case IDB_WM_D: WiiMoteEmu::PadMapping[Controller].Wm.D = Key; break;
+ case IDB_WM_SHAKE: WiiMoteEmu::PadMapping[Controller].Wm.Shake = Key; break;
+ case IDB_WM_PITCH_L: WiiMoteEmu::PadMapping[Controller].Wm.PitchL = Key; break;
+ case IDB_WM_PITCH_R: WiiMoteEmu::PadMapping[Controller].Wm.PitchR = Key; break;
+
+ // Nunchuck
+ case IDB_NC_Z: WiiMoteEmu::PadMapping[Controller].Nc.Z = Key; break;
+ case IDB_NC_C: WiiMoteEmu::PadMapping[Controller].Nc.C = Key; break;
+ case IDB_NC_L: WiiMoteEmu::PadMapping[Controller].Nc.L = Key; break;
+ case IDB_NC_R: WiiMoteEmu::PadMapping[Controller].Nc.R = Key; break;
+ case IDB_NC_U: WiiMoteEmu::PadMapping[Controller].Nc.U = Key; break;
+ case IDB_NC_D: WiiMoteEmu::PadMapping[Controller].Nc.D = Key; break;
+ case IDB_NC_SHAKE: WiiMoteEmu::PadMapping[Controller].Nc.Shake = Key; break;
+
+ // Classic Controller
+ case IDB_CC_A: WiiMoteEmu::PadMapping[Controller].Cc.A = Key; break;
+ case IDB_CC_B: WiiMoteEmu::PadMapping[Controller].Cc.B = Key; break;
+ case IDB_CC_X: WiiMoteEmu::PadMapping[Controller].Cc.X = Key; break;
+ case IDB_CC_Y: WiiMoteEmu::PadMapping[Controller].Cc.Y = Key; break;
+ case IDB_CC_P: WiiMoteEmu::PadMapping[Controller].Cc.P = Key; break;
+ case IDB_CC_M: WiiMoteEmu::PadMapping[Controller].Cc.M = Key; break;
+ case IDB_CC_H: WiiMoteEmu::PadMapping[Controller].Cc.H = Key; break;
+ case IDB_CC_TL: WiiMoteEmu::PadMapping[Controller].Cc.Tl = Key; break;
+ case IDB_CC_ZL: WiiMoteEmu::PadMapping[Controller].Cc.Zl = Key; break;
+ case IDB_CC_ZR: WiiMoteEmu::PadMapping[Controller].Cc.Zr = Key; break;
+ case IDB_CC_TR: WiiMoteEmu::PadMapping[Controller].Cc.Tr = Key; break;
+ case IDB_CC_DL: WiiMoteEmu::PadMapping[Controller].Cc.Dl = Key; break;
+ case IDB_CC_DU: WiiMoteEmu::PadMapping[Controller].Cc.Du = Key; break;
+ case IDB_CC_DR: WiiMoteEmu::PadMapping[Controller].Cc.Dr = Key; break;
+ case IDB_CC_DD: WiiMoteEmu::PadMapping[Controller].Cc.Dd = Key; break;
+ case IDB_CC_LL: WiiMoteEmu::PadMapping[Controller].Cc.Ll = Key; break;
+ case IDB_CC_LU: WiiMoteEmu::PadMapping[Controller].Cc.Lu = Key; break;
+ case IDB_CC_LR: WiiMoteEmu::PadMapping[Controller].Cc.Lr = Key; break;
+ case IDB_CC_LD: WiiMoteEmu::PadMapping[Controller].Cc.Ld = Key; break;
+ case IDB_CC_RL: WiiMoteEmu::PadMapping[Controller].Cc.Rl = Key; break;
+ case IDB_CC_RU: WiiMoteEmu::PadMapping[Controller].Cc.Ru = Key; break;
+ case IDB_CC_RR: WiiMoteEmu::PadMapping[Controller].Cc.Rr = Key; break;
+ case IDB_CC_RD: WiiMoteEmu::PadMapping[Controller].Cc.Rd = Key; break;
+ }
+
+ //INFO_LOG(CONSOLE, "WiiMoteEmu::PadMapping[%i].Wm.A = %i", Controller, WiiMoteEmu::PadMapping[Controller].Wm.A);
+}
+
+// Replace the harder to understand -1 with "" for the sake of user friendliness
+// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
+void ConfigDialog::ToBlank(bool ToBlank)
+{
+ if (!ControlsCreated) return;
+
+ for (int j = 0; j < 1; j++)
+ {
+ if(ToBlank)
+ {
+ for(int i = IDB_ANALOG_LEFT_X; i <= IDB_TRIGGER_R; i++)
+ #ifndef _WIN32
+ if(GetButtonText(i, j).ToAscii() == "-1") SetButtonText(i, "", j);
+ #else
+ if(GetButtonText(i, j) == "-1") SetButtonText(i, "", j);
+ #endif
+ }
+ else
+ {
+ for(int i = IDB_ANALOG_LEFT_X; i <= IDB_TRIGGER_R; i++)
+ if(GetButtonText(i, j).IsEmpty()) SetButtonText(i, "-1", j);
+ }
+ }
+}
+//////////////////////////////////////
+
+
+
+
+// Update the textbox for the buttons
+// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
+void ConfigDialog::SetButtonText(int id, char text[128], int _Page)
+{
+ // Set controller value
+ int controller;
+ if (_Page == -1) controller = Page; else controller = _Page;
+
+ switch(id)
+ {
+ case IDB_ANALOG_LEFT_X: m_AnalogLeftX[controller]->SetValue(wxString::FromAscii(text)); break;
+ case IDB_ANALOG_LEFT_Y: m_AnalogLeftY[controller]->SetValue(wxString::FromAscii(text)); break;
+ case IDB_ANALOG_RIGHT_X: m_AnalogRightX[controller]->SetValue(wxString::FromAscii(text)); break;
+ case IDB_ANALOG_RIGHT_Y: m_AnalogRightY[controller]->SetValue(wxString::FromAscii(text)); break;
+
+ case IDB_TRIGGER_L: m_AnalogTriggerL[controller]->SetValue(wxString::FromAscii(text)); break;
+ case IDB_TRIGGER_R: m_AnalogTriggerR[controller]->SetValue(wxString::FromAscii(text)); break;
+
+ // Wiimote
+ case IDB_WM_A: m_bWmA[controller]->SetLabel(wxString::FromAscii(text)); break;
+ case IDB_WM_B: m_bWmB[controller]->SetLabel(wxString::FromAscii(text)); break;
+ case IDB_WM_1: m_bWm1[controller]->SetLabel(wxString::FromAscii(text)); break;
+ case IDB_WM_2: m_bWm2[controller]->SetLabel(wxString::FromAscii(text)); break;
+ case IDB_WM_P: m_bWmP[controller]->SetLabel(wxString::FromAscii(text)); break;
+ case IDB_WM_M: m_bWmM[controller]->SetLabel(wxString::FromAscii(text)); break;
+ case IDB_WM_H: m_bWmH[controller]->SetLabel(wxString::FromAscii(text)); break;
+ case IDB_WM_L: m_bWmL[controller]->SetLabel(wxString::FromAscii(text)); break;
+ case IDB_WM_R: m_bWmR[controller]->SetLabel(wxString::FromAscii(text)); break;
+ case IDB_WM_U: m_bWmU[controller]->SetLabel(wxString::FromAscii(text)); break;
+ case IDB_WM_D: m_bWmD[controller]->SetLabel(wxString::FromAscii(text)); break;
+ case IDB_WM_SHAKE: m_bWmShake[controller]->SetLabel(wxString::FromAscii(text)); break;
+ case IDB_WM_PITCH_L: m_bWmPitchL[controller]->SetLabel(wxString::FromAscii(text)); break;
+ case IDB_WM_PITCH_R: m_bWmPitchR[controller]->SetLabel(wxString::FromAscii(text)); break;
+
+ // Nunchuck
+ case IDB_NC_Z: m_bNcZ[controller]->SetLabel(wxString::FromAscii(text)); break;
+ case IDB_NC_C: m_bNcC[controller]->SetLabel(wxString::FromAscii(text)); break;
+ case IDB_NC_L: m_bNcL[controller]->SetLabel(wxString::FromAscii(text)); break;
+ case IDB_NC_R: m_bNcR[controller]->SetLabel(wxString::FromAscii(text)); break;
+ case IDB_NC_U: m_bNcU[controller]->SetLabel(wxString::FromAscii(text)); break;
+ case IDB_NC_D: m_bNcD[controller]->SetLabel(wxString::FromAscii(text)); break;
+ case IDB_NC_SHAKE: m_bNcShake[controller]->SetLabel(wxString::FromAscii(text)); break;
+
+ // Classic Controller
+ case IDB_CC_A: m_bCcA[controller]->SetLabel(wxString::FromAscii(text)); break;
+ case IDB_CC_B: m_bCcB[controller]->SetLabel(wxString::FromAscii(text)); break;
+ case IDB_CC_X: m_bCcX[controller]->SetLabel(wxString::FromAscii(text)); break;
+ case IDB_CC_Y: m_bCcY[controller]->SetLabel(wxString::FromAscii(text)); break;
+ case IDB_CC_P: m_bCcP[controller]->SetLabel(wxString::FromAscii(text)); break;
+ case IDB_CC_M: m_bCcM[controller]->SetLabel(wxString::FromAscii(text)); break;
+ case IDB_CC_H: m_bCcH[controller]->SetLabel(wxString::FromAscii(text)); break;
+ case IDB_CC_TL: m_bCcTl[controller]->SetLabel(wxString::FromAscii(text)); break;
+ case IDB_CC_ZL: m_bCcZl[controller]->SetLabel(wxString::FromAscii(text)); break;
+ case IDB_CC_ZR: m_bCcZr[controller]->SetLabel(wxString::FromAscii(text)); break;
+ case IDB_CC_TR: m_bCcTr[controller]->SetLabel(wxString::FromAscii(text)); break;
+ case IDB_CC_DL: m_bCcDl[controller]->SetLabel(wxString::FromAscii(text)); break;
+ case IDB_CC_DU: m_bCcDu[controller]->SetLabel(wxString::FromAscii(text)); break;
+ case IDB_CC_DR: m_bCcDr[controller]->SetLabel(wxString::FromAscii(text)); break;
+ case IDB_CC_DD: m_bCcDd[controller]->SetLabel(wxString::FromAscii(text)); break;
+ case IDB_CC_LL: m_bCcLl[controller]->SetLabel(wxString::FromAscii(text)); break;
+ case IDB_CC_LU: m_bCcLu[controller]->SetLabel(wxString::FromAscii(text)); break;
+ case IDB_CC_LR: m_bCcLr[controller]->SetLabel(wxString::FromAscii(text)); break;
+ case IDB_CC_LD: m_bCcLd[controller]->SetLabel(wxString::FromAscii(text)); break;
+ case IDB_CC_RL: m_bCcRl[controller]->SetLabel(wxString::FromAscii(text)); break;
+ case IDB_CC_RU: m_bCcRu[controller]->SetLabel(wxString::FromAscii(text)); break;
+ case IDB_CC_RR: m_bCcRr[controller]->SetLabel(wxString::FromAscii(text)); break;
+ case IDB_CC_RD: m_bCcRd[controller]->SetLabel(wxString::FromAscii(text)); break;
+ default: break;
+ }
+ //INFO_LOG(CONSOLE, "SetButtonText: %s\n", text);
+}
+
+// Get the text in the textbox for the buttons
+// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
+wxString ConfigDialog::GetButtonText(int id, int _Page)
+{
+ //INFO_LOG(CONSOLE, "GetButtonText: %i\n", id);
+
+ // Set controller value
+ int controller;
+ if (_Page == -1) controller = Page; else controller = _Page;
+
+ switch(id)
+ {
+ // Analog Stick
+ case IDB_ANALOG_LEFT_X: return m_AnalogLeftX[controller]->GetValue();
+ case IDB_ANALOG_LEFT_Y: return m_AnalogLeftY[controller]->GetValue();
+ case IDB_ANALOG_RIGHT_X: return m_AnalogRightX[controller]->GetValue();
+ case IDB_ANALOG_RIGHT_Y: return m_AnalogRightY[controller]->GetValue();
+
+ // Shoulder Buttons
+ case IDB_TRIGGER_L: return m_AnalogTriggerL[controller]->GetValue();
+ case IDB_TRIGGER_R: return m_AnalogTriggerR[controller]->GetValue();
+
+ default: return wxString();
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Configure button mapping
+// ŻŻŻŻŻŻŻŻŻŻ
+
+
+// Wait for button press
+// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
+/* Loop or timer: There are basically two ways to do this. With a while() or for() loop, or with a
+ timer. The downside with the while() or for() loop is that there is no way to stop it if the user
+ should select to configure another button while we are still in an old loop. What will happen then
+ is that we start another parallel loop (at least in Windows) that blocks the old loop. And our only
+ option to wait for the old loop to finish is with a new loop, and that will block the old loop for as
+ long as it's going on. Therefore a timer is easier to control. */
+void ConfigDialog::GetButtons(wxCommandEvent& event)
+{
+ DoGetButtons(event.GetId());
+}
+
+void ConfigDialog::DoGetButtons(int GetId)
+{
+ // =============================================
+ // Collect the starting values
+ // ----------------
+
+ // Get the current controller
+ int Controller = Page;
+ int PadID = WiiMoteEmu::PadMapping[Controller].ID;
+
+ // Get the controller and trigger type
+ int TriggerType = WiiMoteEmu::PadMapping[Controller].triggertype;
+
+ // Collect the accepted buttons for this slot
+ bool LeftRight = (GetId == IDB_TRIGGER_L || GetId == IDB_TRIGGER_R);
+
+ bool Axis = (GetId >= IDB_ANALOG_LEFT_X && GetId <= IDB_TRIGGER_R)
+ // Don't allow SDL axis input for the shoulder buttons if XInput is selected
+ && !(TriggerType == InputCommon::CTL_TRIGGER_XINPUT && (GetId == IDB_TRIGGER_L || GetId == IDB_TRIGGER_R) );
+
+ bool XInput = (TriggerType == InputCommon::CTL_TRIGGER_XINPUT);
+
+ bool Button = false; // No digital buttons allowed
+
+ bool Hat = false; // No hats allowed
+
+ bool NoTriggerFilter = g_Config.bNoTriggerFilter;
+
+ // Values used in this function
+ char format[128];
+ int Seconds = 4; // Seconds to wait for
+ int TimesPerSecond = 40; // How often to run the check
+
+ // Values returned from InputCommon::GetButton()
+ int value; // Axis value
+ int type; // Button type
+ int pressed = 0;
+ bool Succeed = false;
+ bool Stop = false; // Stop the timer
+ // =======================
+
+ //INFO_LOG(CONSOLE, "Before (%i) Id:%i %i IsRunning:%i\n",
+ // GetButtonWaitingTimer, GetButtonWaitingID, GetId, m_ButtonMappingTimer->IsRunning());
+
+ // If the Id has changed or the timer is not running we should start one
+ if( GetButtonWaitingID != GetId || !m_ButtonMappingTimer->IsRunning() )
+ {
+ if(m_ButtonMappingTimer->IsRunning())
+ {
+ m_ButtonMappingTimer->Stop();
+ GetButtonWaitingTimer = 0;
+
+ // Update the old textbox
+ SetButtonText(GetButtonWaitingID, "");
+ }
+
+ // Save the button Id
+ GetButtonWaitingID = GetId;
+
+ // Reset the key in case we happen to have an old one
+ g_Pressed = 0;
+
+ // Update the text box
+ sprintf(format, "[%d]", Seconds);
+ SetButtonText(GetId, format);
+
+ // Start the timer
+ #if wxUSE_TIMER
+ m_ButtonMappingTimer->Start( floor((double)(1000 / TimesPerSecond)) );
+ #endif
+ INFO_LOG(CONSOLE, "Timer Started for Pad:%i GetId:%i\n"
+ "Allowed input is Axis:%i LeftRight:%i XInput:%i Button:%i Hat:%i\n",
+ WiiMoteEmu::PadMapping[Controller].ID, GetId,
+ Axis, LeftRight, XInput, Button, Hat);
+ }
+
+ // ===============================================
+ // Check for buttons
+ // ----------------
+
+ // If there is a timer but we should not create a new one
+ else
+ {
+ InputCommon::GetButton(
+ WiiMoteEmu::joyinfo[PadID].joy, PadID, WiiMoteEmu::joyinfo[PadID].NumButtons, WiiMoteEmu::joyinfo[PadID].NumAxes, WiiMoteEmu::joyinfo[PadID].NumHats,
+ g_Pressed, value, type, pressed, Succeed, Stop,
+ LeftRight, Axis, XInput, Button, Hat, NoTriggerFilter);
+ }
+ // ========================= Check for keys
+
+
+ // ===============================================
+ // Process results
+ // ----------------
+
+ // Count each time
+ GetButtonWaitingTimer++;
+
+ // This is run every second
+ if(GetButtonWaitingTimer % TimesPerSecond == 0)
+ {
+ // Current time
+ int TmpTime = Seconds - (GetButtonWaitingTimer / TimesPerSecond);
+
+ // Update text
+ sprintf(format, "[%d]", TmpTime);
+ SetButtonText(GetId, format);
+
+ /* Debug
+ INFO_LOG(CONSOLE, "Keyboard: %i\n", g_Pressed);*/
+ }
+
+ // Time's up
+ if( (GetButtonWaitingTimer / TimesPerSecond) >= Seconds )
+ {
+ Stop = true;
+ // Leave a blank mapping
+ SetButtonTextAll(GetId, "-1");
+ }
+
+ // If we got a button
+ if(Succeed)
+ {
+ Stop = true;
+ // Write the number of the pressed button to the text box
+ sprintf(format, "%d", pressed);
+ SetButtonTextAll(GetId, format);
+ }
+
+ // Stop the timer
+ if(Stop)
+ {
+ m_ButtonMappingTimer->Stop();
+ GetButtonWaitingTimer = 0;
+
+ /* Update the button mapping for all slots that use this device. (It doesn't make sense to have several slots
+ controlled by the same device, but several DirectInput instances of different but identical devices may possible
+ have the same id, I don't know. So we have to do this. The user may also have selected the same device for
+ several disabled slots. */
+ SaveButtonMappingAll(Controller);
+
+ INFO_LOG(CONSOLE, "Timer Stopped for Pad:%i GetId:%i\n",
+ WiiMoteEmu::PadMapping[Controller].ID, GetId);
+ }
+
+ // If we got a bad button
+ if(g_Pressed == -1)
+ {
+ // Update text
+ SetButtonTextAll(GetId, "-1");
+
+ // Notify the user
+ wxMessageBox(wxString::Format(wxT(
+ "You selected a key with a to low key code (%i), please"
+ " select another key with a higher key code."), pressed)
+ , wxT("Notice"), wxICON_INFORMATION);
+ }
+ // ======================== Process results
+
+ // Debugging
+ /*
+ INFO_LOG(CONSOLE, "Change: %i %i %i %i '%s' '%s' '%s' '%s'\n",
+ WiiMoteEmu::PadMapping[0].halfpress, WiiMoteEmu::PadMapping[1].halfpress, WiiMoteEmu::PadMapping[2].halfpress, WiiMoteEmu::PadMapping[3].halfpress,
+ m_JoyButtonHalfpress[0]->GetValue().c_str(), m_JoyButtonHalfpress[1]->GetValue().c_str(), m_JoyButtonHalfpress[2]->GetValue().c_str(), m_JoyButtonHalfpress[3]->GetValue().c_str()
+ );*/
+}
+/////////////////////////////////////////////////////////// Configure button mapping
+
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Show current input status
+// ŻŻŻŻŻŻŻŻŻŻ
+
+// Convert the 0x8000 range values to BoxW and BoxH for the plot
+void ConfigDialog::Convert2Box(int &x)
+{
+ // Border adjustment
+ int BoxW_ = BoxW - 2; int BoxH_ = BoxH - 2;
+
+ // Convert values
+ x = (BoxW_ / 2) + (x * BoxW_ / (32767 * 2));
+}
+
+// Update the input status boxes
+// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
+void ConfigDialog::PadGetStatus()
+{
+ //INFO_LOG(CONSOLE, "SDL_WasInit: %i\n", SDL_WasInit(0));
+
+ /* Return if it's not detected. The ID should never be less than zero here, it can only be that
+ because of a manual ini file change, but we make that check anway. */
+ if(WiiMoteEmu::PadMapping[Page].ID < 0 || WiiMoteEmu::PadMapping[Page].ID >= SDL_NumJoysticks())
+ {
+ m_TStatusLeftIn[Page]->SetLabel(wxT("Not connected"));
+ m_TStatusLeftOut[Page]->SetLabel(wxT("Not connected"));
+ m_TStatusRightIn[Page]->SetLabel(wxT("Not connected"));
+ m_TStatusRightOut[Page]->SetLabel(wxT("Not connected"));
+ m_TriggerStatusLx[Page]->SetLabel(wxT("0"));
+ m_TriggerStatusRx[Page]->SetLabel(wxT("0"));
+ return;
+ }
+
+ // Return if it's not enabled
+ if (!WiiMoteEmu::PadMapping[Page].enabled)
+ {
+ m_TStatusLeftIn[Page]->SetLabel(wxT("Not enabled"));
+ m_TStatusLeftOut[Page]->SetLabel(wxT("Not enabled"));
+ m_TStatusRightIn[Page]->SetLabel(wxT("Not enabled"));
+ m_TStatusRightOut[Page]->SetLabel(wxT("Not enabled"));
+ m_TriggerStatusLx[Page]->SetLabel(wxT("0"));
+ m_TriggerStatusRx[Page]->SetLabel(wxT("0"));
+ return;
+ }
+
+ // Get physical device status
+ int PhysicalDevice = WiiMoteEmu::PadMapping[Page].ID;
+ int TriggerType = WiiMoteEmu::PadMapping[Page].triggertype;
+
+ // Check that Dolphin is in focus, otherwise don't update the pad status
+ //if (IsFocus())
+ WiiMoteEmu::GetJoyState(WiiMoteEmu::PadState[Page], WiiMoteEmu::PadMapping[Page], Page, WiiMoteEmu::joyinfo.at(WiiMoteEmu::PadMapping[Page].ID).NumButtons);
+
+
+ //////////////////////////////////////
+ // Analog stick
+ // ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
+ // Set Deadzones perhaps out of function
+ //int deadzone = (int)(((float)(128.00/100.00)) * (float)(PadMapping[_numPAD].deadzone+1));
+ //int deadzone2 = (int)(((float)(-128.00/100.00)) * (float)(PadMapping[_numPAD].deadzone+1));
+
+ // Get original values
+ int main_x = WiiMoteEmu::PadState[Page].Axis.Lx;
+ int main_y = WiiMoteEmu::PadState[Page].Axis.Ly;
+ int right_x = WiiMoteEmu::PadState[Page].Axis.Rx;
+ int right_y = WiiMoteEmu::PadState[Page].Axis.Ry;
+
+ // Get adjusted values
+ int main_x_after = main_x, main_y_after = main_y;
+ int right_x_after = right_x, right_y_after = right_y;
+ // Produce square
+ if(WiiMoteEmu::PadMapping[Page].bCircle2Square)
+ {
+ std::vector main_xy = InputCommon::Square2Circle(main_x, main_y, Page, WiiMoteEmu::PadMapping[Page].SDiagonal, true);
+ main_x_after = main_xy.at(0);
+ main_y_after = main_xy.at(1);
+ //main_x = main_xy.at(0);
+ //main_y = main_xy.at(1);
+ }
+ // Check dead zone
+ float DeadZoneLeft = (float)WiiMoteEmu::PadMapping[Page].DeadZoneL / 100.0;
+ float DeadZoneRight = (float)WiiMoteEmu::PadMapping[Page].DeadZoneR / 100.0;
+ if (InputCommon::IsDeadZone(DeadZoneLeft, main_x_after, main_y_after))
+ {
+ main_x_after = 0;
+ main_y_after = 0;
+ }
+ if (InputCommon::IsDeadZone(DeadZoneRight, right_x_after, right_y_after))
+ {
+ right_x_after = 0;
+ right_y_after = 0;
+ }
+
+ // -------------------------------------------
+ // Show the adjusted angles in the status box
+ // --------------
+ // Change 0x8000 to 180
+ /*
+ float x8000 = 0x8000;
+ main_x_after = main_x_after * (180 / x8000);
+ main_y_after = main_y_after * (180 / x8000);
+ float f_main_x_after = (float)main_x_after;
+ float f_main_y_after = (float)main_y_after;
+ WiiMoteEmu::AdjustAngles(f_main_x_after, f_main_y_after);
+ //WiiMoteEmu::AdjustAngles(f_main_x_after, f_main_y_after, true);
+ main_x_after = (int)f_main_x_after;
+ main_y_after = (int)f_main_y_after;
+ // Change back 180 to 0x8000
+ main_x_after = main_x_after * (x8000 / 180);
+ main_y_after = main_y_after * (x8000 / 180);
+ */
+ // ---------------------
+
+ // Convert the values to fractions
+ float f_x = main_x / 32767.0;
+ float f_y = main_y / 32767.0;
+ float f_x_aft = main_x_after / 32767.0;
+ float f_y_aft = main_y_after / 32767.0;
+
+ float f_Rx = right_x / 32767.0;
+ float f_Ry = right_y / 32767.0;
+ float f_Rx_aft = right_x_after / 32767.0;
+ float f_Ry_aft = right_y_after / 32767.0;
+
+ m_TStatusLeftIn[Page]->SetLabel(wxString::Format(
+ wxT("x:%1.2f y:%1.2f"), f_x, f_y
+ ));
+ m_TStatusLeftOut[Page]->SetLabel(wxString::Format(
+ wxT("x:%1.2f y:%1.2f"), f_x_aft, f_y_aft
+ ));
+ m_TStatusRightIn[Page]->SetLabel(wxString::Format(
+ wxT("x:%1.2f y:%1.2f"), f_Rx, f_Ry
+ ));
+ m_TStatusRightOut[Page]->SetLabel(wxString::Format(
+ wxT("x:%1.2f y:%1.2f"), f_Rx_aft, f_Ry_aft
+ ));
+
+ // Adjust the values for the plot
+ Convert2Box(main_x); Convert2Box(main_y);
+ Convert2Box(right_x); Convert2Box(right_y);
+
+ Convert2Box(main_x_after); Convert2Box(main_y_after);
+ Convert2Box(right_x_after); Convert2Box(right_y_after);
+
+ // Adjust the dot
+ m_bmpDotLeftIn[Page]->SetPosition(wxPoint(main_x, main_y));
+ m_bmpDotLeftOut[Page]->SetPosition(wxPoint(main_x_after, main_y_after));
+ m_bmpDotRightIn[Page]->SetPosition(wxPoint(right_x, right_y));
+ m_bmpDotRightOut[Page]->SetPosition(wxPoint(right_x_after, right_y_after));
+ ///////////////////// Analog stick
+
+
+ //////////////////////////////////////
+ // Triggers
+ // ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
+ int TriggerValue = 0;
+
+ // Get the selected keys
+ long Left, Right;
+ m_AnalogTriggerL[Page]->GetValue().ToLong(&Left);
+ m_AnalogTriggerR[Page]->GetValue().ToLong(&Right);
+
+ // Get the trigger values
+ int TriggerLeft = WiiMoteEmu::PadState[Page].Axis.Tl;
+ int TriggerRight = WiiMoteEmu::PadState[Page].Axis.Tr;
+
+ // Convert the triggers values
+ if (WiiMoteEmu::PadMapping[Page].triggertype == InputCommon::CTL_TRIGGER_SDL)
+ {
+ TriggerLeft = InputCommon::Pad_Convert(TriggerLeft);
+ TriggerRight = InputCommon::Pad_Convert(TriggerRight);
+ }
+
+ m_TriggerStatusLx[Page]->SetLabel(wxString::Format(
+ wxT("%03i"), TriggerLeft));
+ m_TriggerStatusRx[Page]->SetLabel(wxString::Format(
+ wxT("%03i"), TriggerRight));
+ ///////////////////// Triggers
+}
+
+// Populate the advanced tab
+// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
+void ConfigDialog::UpdatePad(wxTimerEvent& WXUNUSED(event))
+{
+ // Show the current status
+ /*
+ #ifdef SHOW_PAD_STATUS
+ m_pStatusBar->SetLabel(wxString::Format(
+ "%s", ShowStatus(notebookpage).c_str()
+ ));
+ #endif*/
+
+ //LogMsg("Abc%s\n", ShowStatus(notebookpage).c_str());
+
+ PadGetStatus();
+}
+/////////////////////////////////////////////////////
diff --git a/Source/Plugins/Plugin_Wiimote-testing/Src/ConfigRecording.cpp b/Source/Plugins/Plugin_Wiimote-testing/Src/ConfigRecording.cpp
new file mode 100644
index 0000000000..382a1652b0
--- /dev/null
+++ b/Source/Plugins/Plugin_Wiimote-testing/Src/ConfigRecording.cpp
@@ -0,0 +1,535 @@
+// Copyright (C) 2003-2008 Dolphin Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official SVN repository and contact information can be found at
+// http://code.google.com/p/dolphin-emu/
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Includes
+// ŻŻŻŻŻŻŻŻŻŻŻŻŻ
+//#include "Common.h" // for u16
+#include "CommonTypes.h" // for u16
+#include "IniFile.h"
+#include "Timer.h"
+
+#include "wiimote_real.h" // Local
+#include "wiimote_hid.h"
+#include "main.h"
+#include "ConfigDlg.h"
+#include "Config.h"
+#include "EmuMain.h" // for LoadRecordedMovements()
+#include "EmuSubroutines.h" // for WmRequestStatus
+//////////////////////////////////////
+
+
+
+void ConfigDialog::LoadFile()
+{
+ INFO_LOG(CONSOLE, "LoadFile()\n");
+
+ IniFile file;
+ file.Load(FULL_CONFIG_DIR "WiimoteMovement.ini");
+
+ for (int i = 1; i < (RECORDING_ROWS + 1); i++)
+ {
+ // Temporary storage
+ int iTmp;
+ std::string STmp;
+
+ // Get row name
+ std::string SaveName = StringFromFormat("Recording%i", i);
+
+ // HotKey
+ file.Get(SaveName.c_str(), "HotKeySwitch", &iTmp, 3); m_RecordHotKeySwitch[i]->SetSelection(iTmp);
+ file.Get(SaveName.c_str(), "HotKeyWiimote", &iTmp, 10); m_RecordHotKeyWiimote[i]->SetSelection(iTmp);
+ file.Get(SaveName.c_str(), "HotKeyNunchuck", &iTmp, 10); m_RecordHotKeyNunchuck[i]->SetSelection(iTmp);
+ file.Get(SaveName.c_str(), "HotKeyIR", &iTmp, 10); m_RecordHotKeyIR[i]->SetSelection(iTmp);
+
+ // Movement name
+ file.Get(SaveName.c_str(), "MovementName", &STmp, ""); m_RecordText[i]->SetValue(wxString::FromAscii(STmp.c_str()));
+
+ // Game name
+ file.Get(SaveName.c_str(), "GameName", &STmp, ""); m_RecordGameText[i]->SetValue(wxString::FromAscii(STmp.c_str()));
+
+ // IR Bytes
+ file.Get(SaveName.c_str(), "IRBytes", &STmp, ""); m_RecordIRBytesText[i]->SetValue(wxString::FromAscii(STmp.c_str()));
+
+ // Recording speed
+ file.Get(SaveName.c_str(), "RecordingSpeed", &iTmp, -1);
+ if(iTmp != -1)
+ m_RecordSpeed[i]->SetValue(wxString::Format(wxT("%i"), iTmp));
+ else
+ m_RecordSpeed[i]->SetValue(wxT(""));
+
+ // Playback speed (currently always saved directly after a recording)
+ file.Get(SaveName.c_str(), "PlaybackSpeed", &iTmp, -1); m_RecordPlayBackSpeed[i]->SetSelection(iTmp);
+ }
+}
+void ConfigDialog::SaveFile()
+{
+ INFO_LOG(CONSOLE, "SaveFile\n");
+
+ IniFile file;
+ file.Load(FULL_CONFIG_DIR "WiimoteMovement.ini");
+
+ for(int i = 1; i < (RECORDING_ROWS + 1); i++)
+ {
+ // Get row name
+ std::string SaveName = StringFromFormat("Recording%i", i);
+
+ // HotKey
+ file.Set(SaveName.c_str(), "HotKeySwitch", m_RecordHotKeySwitch[i]->GetSelection());
+ file.Set(SaveName.c_str(), "HotKeyWiimote", m_RecordHotKeyWiimote[i]->GetSelection());
+ file.Set(SaveName.c_str(), "HotKeyNunchuck", m_RecordHotKeyNunchuck[i]->GetSelection());
+ file.Set(SaveName.c_str(), "HotKeyIR", m_RecordHotKeyIR[i]->GetSelection());
+
+ // Movement name
+ file.Set(SaveName.c_str(), "MovementName", m_RecordText[i]->GetValue().c_str());
+
+ // Game name
+ file.Set(SaveName.c_str(), "GameName", m_RecordGameText[i]->GetValue().c_str());
+
+ // Recording speed (currently always saved directly after a recording)
+ /*
+ wxString TmpRecordSpeed = m_RecordSpeed[i]->GetValue();
+ if(TmpRecordSpeed.length() > 0)
+ int TmpRecordSpeed; file.Set(SaveName.c_str(), "RecordingSpeed", TmpRecordSpeed);
+ else
+ int TmpRecordSpeed; file.Set(SaveName.c_str(), "RecordingSpeed", "-1");
+ */
+
+ // Playback speed (currently always saved directly after a recording)
+ file.Set(SaveName.c_str(), "PlaybackSpeed", m_RecordPlayBackSpeed[i]->GetSelection());
+ }
+
+ file.Save(FULL_CONFIG_DIR "WiimoteMovement.ini");
+ INFO_LOG(CONSOLE, "SaveFile()\n");
+}
+/////////////////////////////
+
+
+
+
+
+/////////////////////////////////////////////////////////////////////////
+// Create GUI
+// ------------
+void ConfigDialog::CreateGUIControlsRecording()
+{
+ ////////////////////////////////////////////////////////////////////////////////
+ // Real Wiimote
+ // ----------------
+
+ // ---------------------------------------------
+ // Status
+ // ----------------
+ m_TextUpdateRate = new wxStaticText(m_PageRecording, wxID_ANY, wxT("Update rate: 000 times/s"));
+ m_UpdateMeters = new wxCheckBox(m_PageRecording, ID_UPDATE_REAL, wxT("Update gauges"));
+
+ m_UpdateMeters->SetValue(g_Config.bUpdateRealWiimote);
+
+ m_UpdateMeters->SetToolTip(wxT(
+ "You can turn this off when a game is running to avoid a potential slowdown that may come from redrawing the\n"
+ "configuration screen. Remember that you also need to press '+' on your Wiimote before you can record movements."
+ ));
+ // -----------------------
+
+ // Width and height of the gauges
+ static const int Gw = 35, Gh = 110;
+
+ m_GaugeBattery = new wxGauge( m_PageRecording, wxID_ANY, 100, wxDefaultPosition, wxSize(Gw, Gh), wxGA_VERTICAL | wxNO_BORDER | wxGA_SMOOTH);
+ m_GaugeRoll[0] = new wxGauge( m_PageRecording, wxID_ANY, 360, wxDefaultPosition, wxSize(Gw, Gh), wxGA_VERTICAL | wxNO_BORDER | wxGA_SMOOTH);
+ m_GaugeRoll[1] = new wxGauge( m_PageRecording, wxID_ANY, 360, wxDefaultPosition, wxSize(Gw, Gh), wxGA_VERTICAL | wxNO_BORDER | wxGA_SMOOTH);
+ m_GaugeGForce[0] = new wxGauge( m_PageRecording, wxID_ANY, 600, wxDefaultPosition, wxSize(Gw, Gh), wxGA_VERTICAL | wxNO_BORDER | wxGA_SMOOTH);
+ m_GaugeGForce[1] = new wxGauge( m_PageRecording, wxID_ANY, 600, wxDefaultPosition, wxSize(Gw, Gh), wxGA_VERTICAL | wxNO_BORDER | wxGA_SMOOTH);
+ m_GaugeGForce[2] = new wxGauge( m_PageRecording, wxID_ANY, 600, wxDefaultPosition, wxSize(Gw, Gh), wxGA_VERTICAL | wxNO_BORDER | wxGA_SMOOTH);
+ m_GaugeAccel[0] = new wxGauge( m_PageRecording, wxID_ANY, 255, wxDefaultPosition, wxSize(Gw, Gh), wxGA_VERTICAL | wxNO_BORDER | wxGA_SMOOTH);
+ m_GaugeAccel[1] = new wxGauge( m_PageRecording, wxID_ANY, 255, wxDefaultPosition, wxSize(Gw, Gh), wxGA_VERTICAL | wxNO_BORDER | wxGA_SMOOTH);
+ m_GaugeAccel[2] = new wxGauge( m_PageRecording, wxID_ANY, 255, wxDefaultPosition, wxSize(Gw, Gh), wxGA_VERTICAL | wxNO_BORDER | wxGA_SMOOTH);
+
+ // The text controls
+ m_TextIR = new wxStaticText(m_PageRecording, wxID_ANY, wxT("Cursor: 000 000\nDistance: 0000"));
+
+ // ------------------------------------
+ // The sizers for all gauges together with their label
+ // -----------
+ wxBoxSizer * sBoxBattery = new wxBoxSizer(wxVERTICAL);
+ wxBoxSizer * sBoxRoll[2];
+ sBoxRoll[0] = new wxBoxSizer(wxVERTICAL);
+ sBoxRoll[1] = new wxBoxSizer(wxVERTICAL);
+ wxBoxSizer * sBoxGForce[3];
+ sBoxGForce[0] = new wxBoxSizer(wxVERTICAL);
+ sBoxGForce[1] = new wxBoxSizer(wxVERTICAL);
+ sBoxGForce[2] = new wxBoxSizer(wxVERTICAL);
+ wxBoxSizer * sBoxAccel[3];
+ sBoxAccel[0] = new wxBoxSizer(wxVERTICAL);
+ sBoxAccel[1] = new wxBoxSizer(wxVERTICAL);
+ sBoxAccel[2] = new wxBoxSizer(wxVERTICAL);
+
+ wxStaticText * m_TextBattery = new wxStaticText(m_PageRecording, wxID_ANY, wxT("Batt."), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE);
+ wxStaticText * m_TextRoll = new wxStaticText(m_PageRecording, wxID_ANY, wxT("Roll"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE);
+ wxStaticText * m_TextPitch = new wxStaticText(m_PageRecording, wxID_ANY, wxT("Pitch"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE);
+ wxStaticText *m_TextX[2], *m_TextY[2], *m_TextZ[2];
+ m_TextX[0] = new wxStaticText(m_PageRecording, wxID_ANY, wxT("X"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE); m_TextX[1] = new wxStaticText(m_PageRecording, wxID_ANY, wxT("X"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE);
+ m_TextY[0] = new wxStaticText(m_PageRecording, wxID_ANY, wxT("Y"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE); m_TextY[1] = new wxStaticText(m_PageRecording, wxID_ANY, wxT("Y"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE);
+ m_TextZ[0] = new wxStaticText(m_PageRecording, wxID_ANY, wxT("Z"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE); m_TextZ[1] = new wxStaticText(m_PageRecording, wxID_ANY, wxT("Z"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE);
+ // ----------------
+
+ // ----------------------------------------------
+ // Row 1 Sizers
+ // -----------
+ sBoxBattery->Add(m_GaugeBattery, 0, wxEXPAND | (wxALL), 0); sBoxBattery->Add(m_TextBattery, 0, wxEXPAND | (wxUP), 5);
+
+ sBoxRoll[0]->Add(m_GaugeRoll[0], 0, wxEXPAND | (wxUP | wxDOWN | wxLEFT), 0); sBoxRoll[0]->Add(m_TextRoll, 0, wxEXPAND | (wxUP), 5);
+ sBoxRoll[1]->Add(m_GaugeRoll[1], 0, wxEXPAND | (wxUP | wxDOWN | wxRIGHT), 0); sBoxRoll[1]->Add(m_TextPitch, 0, wxEXPAND | (wxUP), 5);
+
+ sBoxGForce[0]->Add(m_GaugeGForce[0], 0, wxEXPAND | (wxUP | wxDOWN | wxLEFT), 0); sBoxGForce[0]->Add(m_TextX[0], 0, wxEXPAND | (wxUP), 5);
+ sBoxGForce[1]->Add(m_GaugeGForce[1], 0, wxEXPAND | (wxUP | wxDOWN), 0); sBoxGForce[1]->Add(m_TextY[0], 0, wxEXPAND | (wxUP), 5);
+ sBoxGForce[2]->Add(m_GaugeGForce[2], 0, wxEXPAND | (wxUP | wxDOWN | wxRIGHT), 0); sBoxGForce[2]->Add(m_TextZ[0], 0, wxEXPAND | (wxUP), 5);
+
+ sBoxAccel[0]->Add(m_GaugeAccel[0], 0, wxEXPAND | (wxUP | wxDOWN | wxLEFT), 0); sBoxAccel[0]->Add(m_TextX[1], 0, wxEXPAND | (wxUP), 5);
+ sBoxAccel[1]->Add(m_GaugeAccel[1], 0, wxEXPAND | (wxUP | wxDOWN), 0); sBoxAccel[1]->Add(m_TextY[1], 0, wxEXPAND | (wxUP), 5);
+ sBoxAccel[2]->Add(m_GaugeAccel[2], 0, wxEXPAND | (wxUP | wxDOWN | wxRIGHT), 0); sBoxAccel[2]->Add(m_TextZ[1], 0, wxEXPAND | (wxUP), 5);
+
+ wxStaticBoxSizer * sbRealStatus = new wxStaticBoxSizer(wxVERTICAL, m_PageRecording, wxT("Status"));
+ wxStaticBoxSizer * sbRealIR = new wxStaticBoxSizer(wxHORIZONTAL, m_PageRecording, wxT("IR"));
+ wxStaticBoxSizer * sbRealBattery = new wxStaticBoxSizer(wxVERTICAL, m_PageRecording, wxT("Battery"));
+ wxStaticBoxSizer * sbRealRoll = new wxStaticBoxSizer(wxHORIZONTAL, m_PageRecording, wxT("Roll and Pitch"));
+ wxStaticBoxSizer * sbRealGForce = new wxStaticBoxSizer(wxHORIZONTAL, m_PageRecording, wxT("G-Force"));
+ wxStaticBoxSizer * sbRealAccel = new wxStaticBoxSizer(wxHORIZONTAL, m_PageRecording, wxT("Accelerometer"));
+
+ // Status
+ sbRealStatus->Add(m_TextUpdateRate, 0, wxEXPAND | (wxALL), 5);
+ sbRealStatus->Add(m_UpdateMeters, 0, wxEXPAND | (wxLEFT | wxRIGHT | wxDOWN), 5);
+
+ sbRealIR->Add(m_TextIR, 0, wxEXPAND | (wxALL), 5);
+ sbRealBattery->Add(sBoxBattery, 0, wxEXPAND | (wxALL), 5);
+ sbRealRoll->Add(sBoxRoll[0], 0, wxEXPAND | (wxALL), 5); sbRealRoll->Add(sBoxRoll[1], 0, wxEXPAND | (wxALL), 5);
+ sbRealGForce->Add(sBoxGForce[0], 0, wxEXPAND | (wxALL), 5); sbRealGForce->Add(sBoxGForce[1], 0, wxEXPAND | (wxALL), 5); sbRealGForce->Add(sBoxGForce[2], 0, wxEXPAND | (wxALL), 5);
+ sbRealAccel->Add(sBoxAccel[0], 0, wxEXPAND | (wxALL), 5); sbRealAccel->Add(sBoxAccel[1], 0, wxEXPAND | (wxALL), 5); sbRealAccel->Add(sBoxAccel[2], 0, wxEXPAND | (wxALL), 5);
+
+ // Vertical leftmost status
+ wxBoxSizer * sbStatusLeft = new wxBoxSizer(wxVERTICAL);
+ sbStatusLeft->Add(sbRealStatus, 0, wxEXPAND | (wxLEFT), 0);
+ sbStatusLeft->Add(sbRealIR, 0, wxEXPAND | (wxLEFT), 0);
+
+ wxBoxSizer * sbRealWiimoteStatus = new wxBoxSizer(wxHORIZONTAL);
+ sbRealWiimoteStatus->Add(sbStatusLeft, 0, wxEXPAND | (wxLEFT), 0);
+ sbRealWiimoteStatus->Add(sbRealBattery, 0, wxEXPAND | (wxLEFT), 5);
+ sbRealWiimoteStatus->Add(sbRealRoll, 0, wxEXPAND | (wxLEFT), 5);
+ sbRealWiimoteStatus->Add(sbRealGForce, 0, wxEXPAND | (wxLEFT), 5);
+ sbRealWiimoteStatus->Add(sbRealAccel, 0, wxEXPAND | (wxLEFT), 5);
+ // --------------------
+
+ // Tool tips
+ m_GaugeBattery->SetToolTip(wxT("Press '+' to show the current status. Press '-' to stop recording the status."));
+ // ==========================================
+
+
+ // ====================================================================
+ // Record movement
+ // ----------------
+ wxStaticBoxSizer * sbRealRecord = new wxStaticBoxSizer(wxVERTICAL, m_PageRecording, wxT("Record movements"));
+
+ wxArrayString StrHotKeySwitch;
+ StrHotKeySwitch.Add(wxT("Shift"));
+ StrHotKeySwitch.Add(wxT("Ctrl"));
+ StrHotKeySwitch.Add(wxT("Alt"));
+ StrHotKeySwitch.Add(wxT(""));
+
+ wxArrayString StrHotKey;
+ for(int i = 0; i < 10; i++) StrHotKey.Add(wxString::Format(wxT("%i"), i));
+ StrHotKey.Add(wxT(""));
+
+ wxArrayString StrPlayBackSpeed;
+ for(int i = 1; i <= 20; i++) StrPlayBackSpeed.Add(wxString::Format(wxT("%i"), i*25));
+
+ wxBoxSizer * sRealRecord[RECORDING_ROWS + 1];
+
+ wxStaticText * m_TextRec = new wxStaticText(m_PageRecording, wxID_ANY, wxT("Rec."), wxDefaultPosition, wxSize(80, -1), wxALIGN_CENTRE);
+ wxStaticText * m_TextHotKeyWm = new wxStaticText(m_PageRecording, wxID_ANY, wxT("Wiim."), wxDefaultPosition, wxSize(32, -1), wxALIGN_CENTRE);
+ wxStaticText * m_TextHotKeyNc = new wxStaticText(m_PageRecording, wxID_ANY, wxT("Nunc."), wxDefaultPosition, wxSize(32, -1), wxALIGN_CENTRE);
+ wxStaticText * m_TextHotKeyIR = new wxStaticText(m_PageRecording, wxID_ANY, wxT("IR"), wxDefaultPosition, wxSize(32, -1), wxALIGN_CENTRE);
+ wxStaticText * m_TextMovement = new wxStaticText(m_PageRecording, wxID_ANY, wxT("Movement name"), wxDefaultPosition, wxSize(200, -1), wxALIGN_CENTRE);
+ wxStaticText * m_TextGame = new wxStaticText(m_PageRecording, wxID_ANY, wxT("Game name"), wxDefaultPosition, wxSize(200, -1), wxALIGN_CENTRE);
+ wxStaticText * m_TextIRBytes = new wxStaticText(m_PageRecording, wxID_ANY, wxT("IR"), wxDefaultPosition, wxSize(20, -1), wxALIGN_CENTRE);
+ wxStaticText * m_TextRecSpeed = new wxStaticText(m_PageRecording, wxID_ANY, wxT("R. s."), wxDefaultPosition, wxSize(33, -1), wxALIGN_CENTRE);
+ wxStaticText * m_TextPlaySpeed = new wxStaticText(m_PageRecording, wxID_ANY, wxT("Pl. s."), wxDefaultPosition, wxSize(40, -1), wxALIGN_CENTRE);
+
+ // Tool tips
+ m_TextRec->SetToolTip(wxT(
+ "To record a movement first press this button, then start the recording by pressing 'A' on the Wiimote and stop the recording\n"
+ "by letting go of 'A'"));
+ m_TextHotKeyWm->SetToolTip(wxT(
+ "Select a hotkey for playback of Wiimote movements. You can combine it with an"
+ " optional Shift, Ctrl, or Alt switch."
+ ));
+ m_TextHotKeyNc->SetToolTip(wxT(
+ "Select a hotkey for playback of Nunchuck movements"));
+ m_TextHotKeyIR->SetToolTip(wxT(
+ "Select a hotkey for playback of Nunchuck movements"));
+ m_TextRecSpeed->SetToolTip(wxT(
+ "Recording speed in average measurements per second"));
+ m_TextPlaySpeed->SetToolTip(wxT(
+ "Playback speed: A playback speed of 100 means that the playback occurs at the same rate as it was recorded. (You can see the\n"
+ "current update rate in the Status window above when a game is running.) However, if your framerate is only at 50% of full speed\n"
+ "you may want to select a playback rate of 50, because then the game might perceive the playback as a full speed playback. (This\n"
+ "holds if Wiimote_Update() is tied to the framerate, I'm not sure that this is the case. It seemed to vary somewhat with different\n"
+ "framerates but perhaps not enough to say that it was exactly tied to the framerate.) So until this is better understood you'll have\n"
+ "to try different playback rates and see which one that works."
+ ));
+
+ sRealRecord[0] = new wxBoxSizer(wxHORIZONTAL);
+ sRealRecord[0]->Add(m_TextRec, 0, wxEXPAND | (wxLEFT), 5);
+ sRealRecord[0]->Add(m_TextHotKeyWm, 0, wxEXPAND | (wxLEFT), 62);
+ sRealRecord[0]->Add(m_TextHotKeyNc, 0, wxEXPAND | (wxLEFT), 5);
+ sRealRecord[0]->Add(m_TextHotKeyIR, 0, wxEXPAND | (wxLEFT), 5);
+ sRealRecord[0]->Add(m_TextMovement, 0, wxEXPAND | (wxLEFT), 5);
+ sRealRecord[0]->Add(m_TextGame, 0, wxEXPAND | (wxLEFT), 5);
+ sRealRecord[0]->Add(m_TextIRBytes, 0, wxEXPAND | (wxLEFT), 5);
+ sRealRecord[0]->Add(m_TextRecSpeed, 0, wxEXPAND | (wxLEFT), 5);
+ sRealRecord[0]->Add(m_TextPlaySpeed, 0, wxEXPAND | (wxLEFT), 5);
+ sbRealRecord->Add(sRealRecord[0], 0, wxEXPAND | (wxALL), 0);
+
+ for(int i = 1; i < (RECORDING_ROWS + 1); i++)
+ {
+ sRealRecord[i] = new wxBoxSizer(wxHORIZONTAL);
+ m_RecordButton[i] = new wxButton(m_PageRecording, IDB_RECORD + i, wxEmptyString, wxDefaultPosition, wxSize(80, 20), 0, wxDefaultValidator, wxEmptyString);
+ m_RecordHotKeySwitch[i] = new wxChoice(m_PageRecording, IDC_RECORD + i, wxDefaultPosition, wxDefaultSize, StrHotKeySwitch);
+ m_RecordHotKeyWiimote[i] = new wxChoice(m_PageRecording, IDC_RECORD + i, wxDefaultPosition, wxDefaultSize, StrHotKey);
+ m_RecordHotKeyNunchuck[i] = new wxChoice(m_PageRecording, IDC_RECORD + i, wxDefaultPosition, wxDefaultSize, StrHotKey);
+ m_RecordHotKeyIR[i] = new wxChoice(m_PageRecording, IDC_RECORD + i, wxDefaultPosition, wxDefaultSize, StrHotKey);
+ m_RecordText[i] = new wxTextCtrl(m_PageRecording, IDT_RECORD_TEXT, wxT(""), wxDefaultPosition, wxSize(200, 19));
+ m_RecordGameText[i] = new wxTextCtrl(m_PageRecording, IDT_RECORD_GAMETEXT, wxT(""), wxDefaultPosition, wxSize(200, 19));
+ m_RecordIRBytesText[i] = new wxTextCtrl(m_PageRecording, IDT_RECORD_IRBYTESTEXT, wxT(""), wxDefaultPosition, wxSize(25, 19));
+ m_RecordSpeed[i] = new wxTextCtrl(m_PageRecording, IDT_RECORD_SPEED, wxT(""), wxDefaultPosition, wxSize(30, 19), wxTE_READONLY | wxTE_CENTRE);
+ m_RecordPlayBackSpeed[i] = new wxChoice(m_PageRecording, IDT_RECORD_PLAYSPEED, wxDefaultPosition, wxDefaultSize, StrPlayBackSpeed);
+
+ m_RecordText[i]->SetMaxLength(35);
+ m_RecordGameText[i]->SetMaxLength(35);
+ m_RecordIRBytesText[i]->Enable(false);
+ m_RecordSpeed[i]->Enable(false);
+
+ // ------------------------------------
+ // Row 2 Sizers
+ // -----------
+ sRealRecord[i]->Add(m_RecordButton[i], 0, wxEXPAND | (wxLEFT), 5);
+ sRealRecord[i]->Add(m_RecordHotKeySwitch[i], 0, wxEXPAND | (wxLEFT), 5);
+ sRealRecord[i]->Add(m_RecordHotKeyWiimote[i], 0, wxEXPAND | (wxLEFT), 2);
+ sRealRecord[i]->Add(m_RecordHotKeyNunchuck[i], 0, wxEXPAND | (wxLEFT), 2);
+ sRealRecord[i]->Add(m_RecordHotKeyIR[i], 0, wxEXPAND | (wxLEFT), 2);
+ sRealRecord[i]->Add(m_RecordText[i], 0, wxEXPAND | (wxLEFT), 5);
+ sRealRecord[i]->Add(m_RecordGameText[i], 0, wxEXPAND | (wxLEFT), 5);
+ sRealRecord[i]->Add(m_RecordIRBytesText[i], 0, wxEXPAND | (wxLEFT), 5);
+ sRealRecord[i]->Add(m_RecordSpeed[i], 0, wxEXPAND | (wxLEFT), 5);
+ sRealRecord[i]->Add(m_RecordPlayBackSpeed[i], 0, wxEXPAND | (wxLEFT), 5);
+
+ sbRealRecord->Add(sRealRecord[i], 0, wxEXPAND | (wxTOP), 2);
+ }
+ // ==========================================
+
+ // ----------------------------------------------------------------------
+ // Set up sizers for the whole page
+ // ----------------
+ m_sRecordingMain = new wxBoxSizer(wxVERTICAL);
+ m_sRecordingMain->Add(sbRealWiimoteStatus, 0, wxEXPAND | (wxLEFT | wxRIGHT | wxUP), 5);
+ m_sRecordingMain->Add(sbRealRecord, 0, wxEXPAND | (wxLEFT | wxRIGHT | wxDOWN), 5);
+
+ m_PageRecording->SetSizer(m_sRecordingMain);
+}
+/////////////////////////////////
+
+
+/////////////////////////////////////////////////////////////////////////
+/* Record movement */
+// ------------
+
+void ConfigDialog::ConvertToString()
+{
+ // Load ini file
+ IniFile file;
+ file.Load(FULL_CONFIG_DIR "WiimoteMovement.ini");
+ std::string TmpStr = "", TmpIR = "", TmpTime = "";
+
+ for (int i = 0; i < (int)m_vRecording.size(); i++)
+ {
+ // Write the movement data
+ TmpStr += StringFromFormat("%s", m_vRecording.at(i).x >= 0 ? StringFromFormat("+%03i", m_vRecording.at(i).x).c_str() : StringFromFormat("%04i", m_vRecording.at(i).x).c_str());
+ TmpStr += StringFromFormat("%s", m_vRecording.at(i).y >= 0 ? StringFromFormat("+%03i", m_vRecording.at(i).y).c_str() : StringFromFormat("%04i", m_vRecording.at(i).y).c_str());
+ TmpStr += StringFromFormat("%s", m_vRecording.at(i).z >= 0 ? StringFromFormat("+%03i", m_vRecording.at(i).z).c_str() : StringFromFormat("%04i", m_vRecording.at(i).z).c_str());
+ if (i < ((int)m_vRecording.size() - 1)) TmpStr += ",";
+
+ //INFO_LOG(CONSOLE, "%s\n", TmpStr.c_str());
+
+ // Write the IR data
+ TmpIR += ArrayToString(m_vRecording.at(i).IR, IRBytes, 0, 30, false);
+ if (i < ((int)m_vRecording.size() - 1)) TmpIR += ",";
+
+ // Write the timestamps. The upper limit is 99 seconds.
+ int Time = (int)((m_vRecording.at(i).Time - m_vRecording.at(0).Time) * 1000);
+ TmpTime += StringFromFormat("%05i", Time);
+ if (i < ((int)m_vRecording.size() - 1)) TmpTime += ",";
+
+ /* Break just short of the IniFile.cpp byte limit so that we don't crash file.Load() the next time.
+ This limit should never be hit because of the recording limit below. I keep it here just in case. */
+ if(TmpStr.length() > (1024*10 - 10) || TmpIR.length() > (1024*10 - 10) || TmpTime.length() > (1024*10 - 10))
+ {
+ break;
+ PanicAlert("Your recording was to long, the entire recording was not saved.");
+ }
+
+ // Debug
+ INFO_LOG(CONSOLE, "Saved: [%i / %i] %03i %03i %03i\n", i, m_vRecording.size(), m_vRecording.at(i).x, m_vRecording.at(i).y, m_vRecording.at(i).z);
+ }
+
+ // Recordings per second
+ double Recordings = (double)m_vRecording.size();
+ double Time = m_vRecording.at(m_vRecording.size() - 1).Time - m_vRecording.at(0).Time;
+ int Rate = (int)(Recordings / Time);
+
+ // If time or the number of recordings are zero we set the Rate to zero
+ if (Time == 0 || m_vRecording.size() == 0) Rate = 0;
+
+ // Update GUI
+ m_RecordIRBytesText[m_iRecordTo]->SetValue(wxString::Format(wxT("%i"), IRBytes));
+ m_RecordSpeed[m_iRecordTo]->SetValue(wxString::Format(wxT("%i"), Rate));
+
+ // Save file
+ std::string SaveName = StringFromFormat("Recording%i", m_iRecordTo);
+ file.Set(SaveName.c_str(), "Movement", TmpStr.c_str());
+ file.Set(SaveName.c_str(), "IR", TmpIR.c_str());
+ file.Set(SaveName.c_str(), "Time", TmpTime.c_str());
+ file.Set(SaveName.c_str(), "IRBytes", IRBytes);
+ file.Set(SaveName.c_str(), "RecordingSpeed", Rate);
+
+ // Set a default playback speed if none is set already
+ int TmpPlaySpeed; file.Get(SaveName.c_str(), "PlaybackSpeed", &TmpPlaySpeed, -1);
+ if (TmpPlaySpeed == -1)
+ {
+ file.Set(SaveName.c_str(), "PlaybackSpeed", 3);
+ m_RecordPlayBackSpeed[m_iRecordTo]->SetSelection(3);
+ }
+
+ file.Save(FULL_CONFIG_DIR "WiimoteMovement.ini");
+
+ INFO_LOG(CONSOLE, "Save recording to WiimoteMovement.ini\n");
+}
+
+// Timeout the recording
+void ConfigDialog::Update(wxTimerEvent& WXUNUSED(event))
+{
+ m_bWaitForRecording = false;
+ m_bRecording = false;
+ m_RecordButton[m_iRecordTo]->SetLabel(wxT(""));
+ UpdateGUI();
+}
+
+void ConfigDialog::RecordMovement(wxCommandEvent& event)
+{
+ m_iRecordTo = event.GetId() - 2000;
+
+ if(WiiMoteReal::g_MotionSensing)
+ {
+ // Check if there already is a recording here
+ if(m_RecordSpeed[m_iRecordTo]->GetLineLength(0) > 0)
+ {
+ if(!AskYesNo("Do you want to replace the current recording?")) return;
+ }
+ m_RecordButton[m_iRecordTo]->SetLabel(wxT("Hold A"));
+ }
+ else
+ {
+ m_RecordButton[m_iRecordTo]->SetLabel(wxT("Press +"));
+ // This is for usability purposes, it may not be obvious at all that this must be unchecked
+ // for the recording to work
+ for(int i = 0; i < 1; i++) m_UseRealWiimote[i]->SetValue(false); g_Config.bUseRealWiimote = false;
+ return;
+ }
+
+ m_bWaitForRecording = true;
+ m_bAllowA = true;
+ m_bRecording = false;
+
+ UpdateGUI();
+
+ m_TimeoutTimer->Start(5000, true);
+}
+
+void ConfigDialog::DoRecordA(bool Pressed)
+{
+ // Return if we are not waiting or recording
+ if (! (m_bWaitForRecording || m_bRecording)) return;
+
+ // Return if we are waiting but have not pressed A
+ if (m_bWaitForRecording && !Pressed) return;
+
+ // Return if we are recording but are still pressing A
+ if (m_bRecording && Pressed) return;
+
+ //m_bAllowA = false;
+ m_bRecording = Pressed;
+
+ // Start recording, only run this once
+ if(m_bRecording && m_bWaitForRecording)
+ {
+ m_RecordButton[m_iRecordTo]->SetLabel(wxT("Recording..."));
+ m_vRecording.clear(); // Clear the list
+ m_TimeoutTimer->Stop();
+ m_bWaitForRecording = false;
+ }
+ // The recording is done
+ else
+ {
+ m_RecordButton[m_iRecordTo]->SetLabel(wxT("Done"));
+ INFO_LOG(CONSOLE, "Done: %i %i\n", m_bWaitForRecording, m_bRecording);
+ //m_bAllowA = true;
+ ConvertToString();
+ }
+
+ UpdateGUI();
+}
+
+void ConfigDialog::DoRecordMovement(int _x, int _y, int _z, const u8 *_IR, int _IRBytes)
+{
+ //std::string Tmp1 = ArrayToString(_IR, 20, 0, 30);
+ //INFO_LOG(CONSOLE, "DoRecordMovement: %s\n", Tmp1.c_str());
+
+ if (!m_bRecording) return;
+
+ //INFO_LOG(CONSOLE, "DoRecordMovement: %03i %03i %03i\n", _x, _y, _z);
+
+ SRecording Tmp;
+ Tmp.x = _x;
+ Tmp.y = _y;
+ Tmp.z = _z;
+ Tmp.Time = GetDoubleTime();
+ memcpy(Tmp.IR, _IR, _IRBytes);
+ m_vRecording.push_back(Tmp);
+
+ // Save the number of IR bytes
+ IRBytes = _IRBytes;
+
+ /* The upper limit of a recording coincides with the IniFile.cpp limit, each list element
+ is 7 bytes, therefore be divide by 7 */
+ if (m_vRecording.size() > (10*1024 / 7 - 2) )
+ {
+ m_bRecording = false;
+ m_RecordButton[m_iRecordTo]->SetLabel(wxT("Done"));
+ ConvertToString();
+ UpdateGUI();
+ }
+}
+/////////////////////////////////
+
diff --git a/Source/Plugins/Plugin_Wiimote-testing/Src/DataReports.cpp b/Source/Plugins/Plugin_Wiimote-testing/Src/DataReports.cpp
new file mode 100644
index 0000000000..7c0a27e260
--- /dev/null
+++ b/Source/Plugins/Plugin_Wiimote-testing/Src/DataReports.cpp
@@ -0,0 +1,301 @@
+// Copyright (C) 2003-2008 Dolphin Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official SVN repository and contact information can be found at
+// http://code.google.com/p/dolphin-emu/
+
+
+
+
+// ===================================================
+/* Data reports guide. The different structures location in the Input reports. The ? in
+ the IR coordinates is the High coordinates that are four in one byte.
+
+ 0x37: For the data reportingmode 0x37 there are five unused IR bytes in the end (represented)
+ by "..." below, it seems like they can be set to either 0xff or 0x00 without affecting the
+ IR emulation. */
+// ----------------
+
+/* 0x33
+ [c.left etc] [c.a etc] acc.x y z ir0.x y ? ir1.x y ? ir2.x y ? ir3.x y ?
+
+ 0x37
+ [c.left etc] [c.a etc] acc.x y z ir0.x1 y1 ? x2 y2 ir1.x1 y1 ? x2 y2 ... ext.jx jy ax ay az bt
+
+
+ The Data Report's path from here is
+ WII_IPC_HLE_WiiMote.cpp:
+ Callback_WiimoteInput()
+ CWII_IPC_HLE_WiiMote::SendL2capData()
+ WII_IPC_HLE_Device_usb.cpp:
+ CWII_IPC_HLE_Device_usb_oh1_57e_305::SendACLFrame()
+ at that point the message is queued and will be sent by the next
+ CWII_IPC_HLE_Device_usb_oh1_57e_305::Update() */
+
+// ================
+
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Includes
+// ŻŻŻŻŻŻŻŻŻŻŻŻŻ
+#include "pluginspecs_wiimote.h"
+
+#include
+#include
+
+#include "Common.h" // Common
+#include "StringUtil.h" // for ArrayToString
+
+#include "wiimote_hid.h" // Local
+#include "main.h"
+#include "EmuMain.h"
+#include "EmuSubroutines.h"
+#include "EmuDefinitions.h"
+#include "Encryption.h" // for extension encryption
+#include "Logging.h" // for startConsoleWin, Console::Print, GetConsoleHwnd
+#include "Config.h" // for g_Config
+///////////////////////////////////
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Declarations and definitions
+// ŻŻŻŻŻŻŻŻŻŻŻŻŻ
+extern SWiimoteInitialize g_WiimoteInitialize;
+///////////////////////////////
+
+
+namespace WiiMoteEmu
+{
+
+//******************************************************************************
+// Subroutines
+//******************************************************************************
+
+
+// ===================================================
+/* Update the data reporting mode */
+// ----------------
+void WmDataReporting(u16 _channelID, wm_data_reporting* dr)
+{
+ INFO_LOG(WII_IPC_WIIMOTE, "===========================================================");
+ DEBUG_LOG(WII_IPC_WIIMOTE, " Set Data reporting mode");
+ DEBUG_LOG(WII_IPC_WIIMOTE, " Rumble: %x", dr->rumble);
+ DEBUG_LOG(WII_IPC_WIIMOTE, " Continuous: %x", dr->continuous);
+ DEBUG_LOG(WII_IPC_WIIMOTE, " All The Time: %x (not only on data change)", dr->all_the_time);
+ DEBUG_LOG(WII_IPC_WIIMOTE, " Mode: 0x%02x", dr->mode);
+ INFO_LOG(CONSOLE, "Data reporting:\n");
+ INFO_LOG(CONSOLE, " Continuous: %x\n", dr->continuous);
+ INFO_LOG(CONSOLE, " All The Time: %x (not only on data change)\n", dr->all_the_time);
+ INFO_LOG(CONSOLE, " Mode: 0x%02x\n", dr->mode);
+ INFO_LOG(CONSOLE, " Channel: 0x%04x\n", _channelID);
+
+ g_ReportingMode = dr->mode;
+ g_ReportingChannel = _channelID;
+ switch(dr->mode) // See Wiimote_Update()
+ {
+ case WM_REPORT_CORE:
+ case WM_REPORT_CORE_ACCEL:
+ case WM_REPORT_CORE_ACCEL_IR12:
+ case WM_REPORT_CORE_ACCEL_EXT16:
+ case WM_REPORT_CORE_ACCEL_IR10_EXT6:
+ break;
+ default:
+ PanicAlert("Wiimote: Unsupported reporting mode 0x%x", dr->mode);
+ }
+
+ // WmSendAck(_channelID, WM_DATA_REPORTING);
+
+ INFO_LOG(WII_IPC_WIIMOTE, "===========================================================");
+}
+
+
+
+// ===================================================
+/* Case 0x30: Core Buttons */
+// ----------------
+void SendReportCore(u16 _channelID)
+{
+ u8 DataFrame[1024];
+ u32 Offset = WriteWmReport(DataFrame, WM_REPORT_CORE);
+
+ wm_report_core* pReport = (wm_report_core*)(DataFrame + Offset);
+ Offset += sizeof(wm_report_core);
+ memset(pReport, 0, sizeof(wm_report_core));
+#if defined(HAVE_WX) && HAVE_WX
+ FillReportInfo(pReport->c);
+#endif
+
+ INFO_LOG(WII_IPC_WIIMOTE, " SendReportCore()");
+
+ g_WiimoteInitialize.pWiimoteInput(_channelID, DataFrame, Offset);
+
+ // Debugging
+ ReadDebugging(true, DataFrame, Offset);
+}
+
+
+// ===================================================
+/* 0x31: Core Buttons and Accelerometer */
+// ----------------
+void SendReportCoreAccel(u16 _channelID)
+{
+ u8 DataFrame[1024];
+ u32 Offset = WriteWmReport(DataFrame, WM_REPORT_CORE_ACCEL);
+
+ wm_report_core_accel* pReport = (wm_report_core_accel*)(DataFrame + Offset);
+ Offset += sizeof(wm_report_core_accel);
+ memset(pReport, 0, sizeof(wm_report_core_accel));
+
+#if defined(HAVE_WX) && HAVE_WX
+ FillReportInfo(pReport->c);
+ FillReportAcc(pReport->a);
+#endif
+
+ INFO_LOG(WII_IPC_WIIMOTE, " SendReportCoreAccel (0x31)");
+ INFO_LOG(WII_IPC_WIIMOTE, " Channel: %04x", _channelID);
+ INFO_LOG(WII_IPC_WIIMOTE, " Offset: %08x", Offset);
+
+ g_WiimoteInitialize.pWiimoteInput(_channelID, DataFrame, Offset);
+
+ // Debugging
+ ReadDebugging(true, DataFrame, Offset);
+}
+
+
+// ===================================================
+/* Case 0x33: Core Buttons and Accelerometer with 12 IR bytes */
+// ----------------
+void SendReportCoreAccelIr12(u16 _channelID) {
+ u8 DataFrame[1024];
+ u32 Offset = WriteWmReport(DataFrame, WM_REPORT_CORE_ACCEL_IR12);
+
+ wm_report_core_accel_ir12* pReport = (wm_report_core_accel_ir12*)(DataFrame + Offset);
+ Offset += sizeof(wm_report_core_accel_ir12);
+ memset(pReport, 0, sizeof(wm_report_core_accel_ir12));
+
+#if defined(HAVE_WX) && HAVE_WX
+ FillReportInfo(pReport->c);
+ FillReportAcc(pReport->a);
+
+ // We settle with emulating two objects, not all four. We leave object 2 and 3 with 0xff.
+ FillReportIR(pReport->ir[0], pReport->ir[1]);
+#endif
+ memset(&pReport->ir[2], 0xff, sizeof(wm_ir_extended));
+ memset(&pReport->ir[3], 0xff, sizeof(wm_ir_extended));
+
+ INFO_LOG(WII_IPC_WIIMOTE, " SendReportCoreAccelIr12()");
+ INFO_LOG(WII_IPC_WIIMOTE, " Offset: %08x", Offset);
+
+ g_WiimoteInitialize.pWiimoteInput(_channelID, DataFrame, Offset);
+
+ // Debugging
+ ReadDebugging(true, DataFrame, Offset);
+}
+
+
+// ===================================================
+/* Case 0x35: Core Buttons and Accelerometer with 16 Extension Bytes */
+// ----------------
+void SendReportCoreAccelExt16(u16 _channelID)
+{
+ u8 DataFrame[1024];
+ u32 Offset = WriteWmReport(DataFrame, WM_REPORT_CORE_ACCEL_EXT16);
+
+ wm_report_core_accel_ext16* pReport = (wm_report_core_accel_ext16*)(DataFrame + Offset);
+ Offset += sizeof(wm_report_core_accel_ext16);
+ memset(pReport, 0, sizeof(wm_report_core_accel_ext16));
+
+ // Make a classic extension struct
+ wm_classic_extension _ext;
+ memset(&_ext, 0, sizeof(wm_classic_extension));
+
+#if defined(HAVE_WX) && HAVE_WX
+ FillReportInfo(pReport->c);
+ FillReportAcc(pReport->a);
+#endif
+
+ if(g_Config.bNunchuckConnected)
+ {
+#if defined(HAVE_WX) && HAVE_WX
+ FillReportExtension(pReport->ext);
+#endif
+ }
+ else if(g_Config.bClassicControllerConnected)
+ {
+#if defined(HAVE_WX) && HAVE_WX
+ FillReportClassicExtension(_ext);
+#endif
+ // Copy _ext to pReport->ext
+ memcpy(&pReport->ext, &_ext, sizeof(_ext));
+ }
+
+ INFO_LOG(WII_IPC_WIIMOTE, " SendReportCoreAccelExt16 (0x35)");
+ INFO_LOG(WII_IPC_WIIMOTE, " Channel: %04x", _channelID);
+ INFO_LOG(WII_IPC_WIIMOTE, " Offset: %08x", Offset);
+
+ g_WiimoteInitialize.pWiimoteInput(_channelID, DataFrame, Offset);
+
+ // Debugging
+ ReadDebugging(true, DataFrame, Offset);
+}
+
+
+// ===================================================
+/* Case 0x37: Core Buttons and Accelerometer with 10 IR bytes and 6 Extension Bytes */
+// ----------------
+void SendReportCoreAccelIr10Ext(u16 _channelID)
+{
+ u8 DataFrame[1024];
+ u32 Offset = WriteWmReport(DataFrame, WM_REPORT_CORE_ACCEL_IR10_EXT6);
+
+ wm_report_core_accel_ir10_ext6* pReport = (wm_report_core_accel_ir10_ext6*)(DataFrame + Offset);
+ Offset += sizeof(wm_report_core_accel_ir10_ext6);
+ memset(pReport, 0, sizeof(wm_report_core_accel_ir10_ext6));
+
+ // Make a classic extension struct
+ wm_classic_extension _ext;
+ memset(&_ext, 0, sizeof(wm_classic_extension));
+
+#if defined(HAVE_WX) && HAVE_WX
+ FillReportInfo(pReport->c);
+ FillReportAcc(pReport->a);
+ FillReportIRBasic(pReport->ir[0], pReport->ir[1]);
+#endif
+
+ if(g_Config.bNunchuckConnected)
+ {
+#if defined(HAVE_WX) && HAVE_WX
+ FillReportExtension(pReport->ext);
+#endif
+ }
+ else if(g_Config.bClassicControllerConnected)
+ {
+#if defined(HAVE_WX) && HAVE_WX
+ FillReportClassicExtension(_ext);
+#endif
+ // Copy _ext to pReport->ext
+ memcpy(&pReport->ext, &_ext, sizeof(_ext));
+ }
+
+ INFO_LOG(WII_IPC_WIIMOTE, " SendReportCoreAccelIr10Ext()");
+
+ g_WiimoteInitialize.pWiimoteInput(_channelID, DataFrame, Offset);
+
+ // Debugging
+ ReadDebugging(true, DataFrame, Offset);
+}
+
+
+} // end of namespace
diff --git a/Source/Plugins/Plugin_Wiimote-testing/Src/EmuDefinitions.cpp b/Source/Plugins/Plugin_Wiimote-testing/Src/EmuDefinitions.cpp
new file mode 100644
index 0000000000..797f3c539f
--- /dev/null
+++ b/Source/Plugins/Plugin_Wiimote-testing/Src/EmuDefinitions.cpp
@@ -0,0 +1,77 @@
+// Copyright (C) 2003-2008 Dolphin Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official SVN repository and contact information can be found at
+// http://code.google.com/p/dolphin-emu/
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Includes
+// ŻŻŻŻŻŻŻŻŻŻŻŻŻ
+#ifndef _EMU_DEFINITIONS_
+#define _EMU_DEFINITIONS_
+
+#include
+#include
+
+#include "pluginspecs_wiimote.h"
+#include "Common.h"
+#include "wiimote_hid.h"
+#include "EmuDefinitions.h"
+#include "Encryption.h"
+#include "Logging.h" // for startConsoleWin, Console::Print, GetConsoleHwnd
+//////////////////////////
+
+extern SWiimoteInitialize g_WiimoteInitialize;
+
+namespace WiiMoteEmu
+{
+
+//******************************************************************************
+// Definitions and variable declarations
+//******************************************************************************
+
+u8 g_Leds;
+u8 g_Speaker;
+u8 g_SpeakerVoice;
+u8 g_IR;
+
+u8 g_Eeprom[WIIMOTE_EEPROM_SIZE];
+u8 g_RegSpeaker[WIIMOTE_REG_SPEAKER_SIZE];
+u8 g_RegExt[WIIMOTE_REG_EXT_SIZE];
+u8 g_RegExtTmp[WIIMOTE_REG_EXT_SIZE];
+u8 g_RegIr[WIIMOTE_REG_IR_SIZE];
+
+u8 g_ReportingMode; // The reporting mode and channel id
+u16 g_ReportingChannel;
+
+std::vector AckDelay; // Ackk delay
+
+wiimote_key g_ExtKey; // The extension encryption key
+bool g_Encryption; // Encryption on or off
+
+// Gamepad input
+int NumPads = 0, NumGoodPads = 0; // Number of goods pads
+std::vector joyinfo;
+InputCommon::CONTROLLER_STATE_NEW PadState[4];
+InputCommon::CONTROLLER_MAPPING_NEW PadMapping[4];
+
+// Keyboard input
+KeyboardWiimote g_Wm;
+KeyboardNunchuck g_Nc;
+KeyboardClassicController g_Cc;
+
+} // namespace
+
+#endif //_EMU_DECLARATIONS_
+
diff --git a/Source/Plugins/Plugin_Wiimote-testing/Src/EmuDefinitions.h b/Source/Plugins/Plugin_Wiimote-testing/Src/EmuDefinitions.h
new file mode 100644
index 0000000000..2c56e82973
--- /dev/null
+++ b/Source/Plugins/Plugin_Wiimote-testing/Src/EmuDefinitions.h
@@ -0,0 +1,249 @@
+// Copyright (C) 2003-2008 Dolphin Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official SVN repository and contact information can be found at
+// http://code.google.com/p/dolphin-emu/
+
+#ifndef _EMU_DECLARATIONS_
+#define _EMU_DECLARATIONS_
+
+#include
+#include
+
+#include "../../../Core/InputCommon/Src/SDL.h" // Core
+#include "../../../Core/InputCommon/Src/XInput.h"
+
+#include "Common.h"
+#include "pluginspecs_wiimote.h"
+
+#include "wiimote_hid.h" // Local
+#include "Encryption.h"
+#include "Logging.h" // for startConsoleWin, Console::Print, GetConsoleHwnd
+
+extern SWiimoteInitialize g_WiimoteInitialize;
+
+namespace WiiMoteEmu
+{
+
+//******************************************************************************
+// Definitions and variable declarations
+//******************************************************************************
+
+/* The Libogc bounding box in smoothed IR coordinates is 232,284 792,704. However, there is no
+ universal standard that works with all games. They all use their own calibration. Also,
+ there is no widescreen mode for the calibration, at least not in the games I tried, the
+ game decides for example that a horizontal value of 500 is 50% from the left of the screen,
+ and then that's the same regardless if we use the widescreen mode or not.*/
+#define LEFT 266
+#define TOP 215
+#define RIGHT 752
+#define BOTTOM 705
+/* Since the width of the entire virtual screen is 1024 a reasonable sensor bar width is perhaps 200,
+ given how small most sensor bars are compared to the total TV width. When I tried the distance with
+ my Wiimote from around three meters distance from the sensor bar (that has around 15 cm beteen the
+ IR lights) I got a dot distance of around 110 (and a dot size of between 1 and 2). */
+#define SENSOR_BAR_RADIUS 100
+
+// Movement recording
+extern int g_RecordingPlaying[3];
+extern int g_RecordingCounter[3];
+extern int g_RecordingPoint[3];
+extern double g_RecordingStart[3];
+extern double g_RecordingCurrentTime[3];
+
+// Registry sizes
+#define WIIMOTE_EEPROM_SIZE (16*1024)
+#define WIIMOTE_EEPROM_FREE_SIZE 0x16ff
+#define WIIMOTE_REG_SPEAKER_SIZE 10
+#define WIIMOTE_REG_EXT_SIZE 0x100
+#define WIIMOTE_REG_IR_SIZE 0x34
+
+extern u8 g_Leds;
+extern u8 g_Speaker;
+extern u8 g_SpeakerVoice;
+extern u8 g_IR;
+
+extern u8 g_Eeprom[WIIMOTE_EEPROM_SIZE];
+extern u8 g_RegSpeaker[WIIMOTE_REG_SPEAKER_SIZE];
+extern u8 g_RegExt[WIIMOTE_REG_EXT_SIZE];
+extern u8 g_RegExtTmp[WIIMOTE_REG_EXT_SIZE];
+extern u8 g_RegIr[WIIMOTE_REG_IR_SIZE];
+
+extern u8 g_ReportingMode;
+extern u16 g_ReportingChannel;
+
+// Ack delay
+struct wm_ackdelay
+{
+ u8 Delay;
+ u8 ReportID;
+ u16 ChannelID;
+ bool Sent;
+};
+extern std::vector AckDelay;
+
+extern wiimote_key g_ExtKey; // extension encryption key
+extern bool g_Encryption;
+
+/* An example of a factory default first bytes of the Eeprom memory. There are differences between
+ different Wiimotes, my Wiimote had different neutral values for the accelerometer. */
+static const u8 EepromData_0[] = {
+ 0xA1, 0xAA, 0x8B, 0x99, 0xAE, 0x9E, 0x78, 0x30, 0xA7, 0x74, 0xD3,
+ 0xA1, 0xAA, 0x8B, 0x99, 0xAE, 0x9E, 0x78, 0x30, 0xA7, 0x74, 0xD3,
+ // Accelerometer neutral values
+ 0x82, 0x82, 0x82, 0x15, 0x9C, 0x9C, 0x9E, 0x38, 0x40, 0x3E,
+ 0x82, 0x82, 0x82, 0x15, 0x9C, 0x9C, 0x9E, 0x38, 0x40, 0x3E
+};
+
+static const u8 EepromData_16D0[] = {
+ 0x00, 0x00, 0x00, 0xFF, 0x11, 0xEE, 0x00, 0x00,
+ 0x33, 0xCC, 0x44, 0xBB, 0x00, 0x00, 0x66, 0x99,
+ 0x77, 0x88, 0x00, 0x00, 0x2B, 0x01, 0xE8, 0x13
+};
+
+
+/* Default calibration for the nunchuck. It should be written to 0x20 - 0x3f of the
+ extension register. 0x80 is the neutral x and y accelerators and 0xb3 is the
+ neutral z accelerometer that is adjusted for gravity. */
+static const u8 nunchuck_calibration[] =
+{
+ 0x80,0x80,0x80,0x00, // accelerometer x, y, z neutral
+ 0xb3,0xb3,0xb3,0x00, // x, y, z g-force values
+
+ 0xff, 0x00, 0x80, 0xff, // 0x80 = analog stick x and y axis center
+ 0x00, 0x80, 0xee, 0x43 // checksum on the last two bytes
+};
+static const u8 wireless_nunchuck_calibration[] =
+{
+ 128, 128, 128, 0x00,
+ 181, 181, 181, 0x00,
+ 255, 0, 125, 255,
+ 0, 126, 0xed, 0x43
+};
+
+/* Classic Controller calibration */
+static const u8 classic_calibration[] =
+{
+ 0xff,0x00,0x80, 0xff,0x00,0x80, 0xff,0x00,0x80, 0xff,0x00,0x80,
+ 0x00,0x00, 0x51,0xa6
+};
+
+
+
+/* The Nunchuck id. It should be written to the last bytes of the
+ extension register */
+static const u8 nunchuck_id[] =
+{
+ 0x00, 0x00, 0xa4, 0x20, 0x00, 0x00
+};
+
+/* The Classic Controller id. It should be written to the last bytes of the
+ extension register */
+static const u8 classic_id[] =
+{
+ 0x00, 0x00, 0xa4, 0x20, 0x01, 0x01
+};
+
+/* The id for nothing inserted */
+static const u8 nothing_id[] =
+{
+ 0x00, 0x00, 0x00, 0x00, 0x2e, 0x2e
+};
+
+/* The id for a partially inserted extension */
+static const u8 partially_id[] =
+{
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff
+};
+
+// Gamepad input
+extern int NumPads, NumGoodPads; // Number of goods pads
+extern std::vector joyinfo;
+extern InputCommon::CONTROLLER_STATE_NEW PadState[4];
+extern InputCommon::CONTROLLER_MAPPING_NEW PadMapping[4];
+
+// Wiimote status
+struct SDot
+{
+ int Rx, Ry, X, Y;
+ bool Visible;
+ int Size; // Size of the IR dot (0-15)
+ int Order; // Increasing order from low to higher x-axis values
+};
+struct SIR
+{
+ SDot Dot[4];
+ int Distance;
+};
+
+// Keyboard input
+struct KeyboardWiimote
+{
+ enum EKeyboardWiimote
+ {
+ A = 0, MA, // Keyboard A and Mouse A
+ B, MB,
+ ONE, TWO,
+ P, M, H,
+ L, R, U, D,
+ PITCH_L, PITCH_R,
+ SHAKE,
+ LAST_CONSTANT
+ };
+
+ // Raw X and Y coordinate and processed X and Y coordinates
+ SIR IR;
+};
+extern KeyboardWiimote g_Wm;
+struct KeyboardNunchuck
+{
+ enum EKeyboardNunchuck
+ {
+ // This is not allowed in Linux so we have to set the starting value manually
+ #ifdef _WIN32
+ Z = g_Wm.LAST_CONSTANT,
+ #else
+ Z = 16,
+ #endif
+ C,
+ L, R, U, D,
+ SHAKE,
+ LAST_CONSTANT
+ };
+};
+extern KeyboardNunchuck g_Nc;
+struct KeyboardClassicController
+{
+ enum EKeyboardClassicController
+ {
+ // This is not allowed in Linux so we have to set the starting value manually
+ #ifdef _WIN32
+ A = g_Nc.LAST_CONSTANT,
+ #else
+ A = 23,
+ #endif
+ B, X, Y,
+ P, M, H,
+ Dl, Dr, Du, Dd,
+ Tl, Tr, Zl, Zr,
+ Ll, Lr, Lu, Ld,
+ Rl, Rr, Ru, Rd,
+ SHAKE
+ };
+};
+extern KeyboardClassicController g_Cc;
+
+} // namespace
+
+#endif //_EMU_DEFINITIONS_
diff --git a/Source/Plugins/Plugin_Wiimote-testing/Src/EmuDynamics.cpp b/Source/Plugins/Plugin_Wiimote-testing/Src/EmuDynamics.cpp
new file mode 100644
index 0000000000..4e9841c4a8
--- /dev/null
+++ b/Source/Plugins/Plugin_Wiimote-testing/Src/EmuDynamics.cpp
@@ -0,0 +1,383 @@
+// Copyright (C) 2003-2008 Dolphin Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official SVN repository and contact information can be found at
+// http://code.google.com/p/dolphin-emu/
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Includes
+// ŻŻŻŻŻŻŻŻŻŻŻŻŻ
+#include
+#include
+
+#include "../../../Core/InputCommon/Src/SDL.h" // Core
+#include "../../../Core/InputCommon/Src/XInput.h"
+
+#include "Common.h" // Common
+#include "MathUtil.h"
+#include "StringUtil.h" // for ArrayToString()
+#include "IniFile.h"
+#include "pluginspecs_wiimote.h"
+
+#include "EmuDefinitions.h" // Local
+#include "main.h"
+#include "wiimote_hid.h"
+#include "EmuSubroutines.h"
+#include "EmuMain.h"
+#include "Encryption.h" // for extension encryption
+#include "Logging.h" // for startConsoleWin, Console::Print, GetConsoleHwnd
+#include "Config.h" // for g_Config
+////////////////////////////////////
+
+
+namespace WiiMoteEmu
+{
+
+
+//******************************************************************************
+// Accelerometer functions
+//******************************************************************************
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Test the calculations
+// ŻŻŻŻŻŻŻŻŻŻŻŻŻ
+void TiltTest(u8 x, u8 y, u8 z)
+{
+ int Roll, Pitch, RollAdj, PitchAdj;
+ PitchAccelerometerToDegree(x, y, z, Roll, Pitch, RollAdj, PitchAdj);
+ std::string From = StringFromFormat("From: X:%i Y:%i Z:%i Roll:%s Pitch:%s", x, y, z,
+ (Roll >= 0) ? StringFromFormat(" %03i", Roll).c_str() : StringFromFormat("%04i", Roll).c_str(),
+ (Pitch >= 0) ? StringFromFormat(" %03i", Pitch).c_str() : StringFromFormat("%04i", Pitch).c_str());
+
+ float _Roll = (float)Roll, _Pitch = (float)Pitch;
+ PitchDegreeToAccelerometer(_Roll, _Pitch, x, y, z);
+ std::string To = StringFromFormat("%s\nTo: X:%i Y:%i Z:%i Roll:%s Pitch:%s", From.c_str(), x, y, z,
+ (_Roll >= 0) ? StringFromFormat(" %03i", (int)_Roll).c_str() : StringFromFormat("%04i", (int)_Roll).c_str(),
+ (_Pitch >= 0) ? StringFromFormat(" %03i", (int)_Pitch).c_str() : StringFromFormat("%04i", (int)_Pitch).c_str());
+ INFO_LOG(CONSOLE, "%s\n", To.c_str());
+}
+////////////////////////////////////
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+/* Angles adjustment for the upside down state when both roll and pitch is used. When the absolute values
+ of the angles go over 90° the Wiimote is upside down and these adjustments are needed. */
+// ŻŻŻŻŻŻŻŻŻŻŻŻŻ
+void AdjustAngles(float &Roll, float &Pitch)
+{
+ float OldPitch = Pitch;
+
+ if (abs(Roll) > 90)
+ {
+ if (Pitch >= 0)
+ Pitch = 180 - Pitch; // 15 to 165
+ else if (Pitch < 0)
+ Pitch = -180 - Pitch; // -15 to -165
+ }
+
+ if (abs(OldPitch) > 90)
+ {
+ if (Roll >= 0)
+ Roll = 180 - Roll; // 15 to 165
+ else if (Roll < 0)
+ Roll = -180 - Roll; // -15 to -165
+ }
+}
+////////////////////////////////////
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Angles to accelerometer values
+// ŻŻŻŻŻŻŻŻŻŻŻŻŻ
+void PitchDegreeToAccelerometer(float _Roll, float _Pitch, u8 &_x, u8 &_y, u8 &_z)
+{
+ // We need radiands for the math functions
+ _Roll = InputCommon::Deg2Rad(_Roll);
+ _Pitch = InputCommon::Deg2Rad(_Pitch);
+ // We need decimal values
+ float x = (float)_x, y = (float)_y, z = (float)_z;
+
+ // In these cases we can use the simple and accurate formula
+ if(g_Config.Trigger.Range.Pitch == 0)
+ {
+ x = sin(_Roll);
+ z = cos(_Roll);
+ }
+ else if (g_Config.Trigger.Range.Roll == 0)
+ {
+
+ y = sin(_Pitch);
+ z = cos(_Pitch);
+ }
+ else
+ {
+ // ====================================================
+ /* This seems to always produce the exact same combination of x, y, z and Roll and Pitch that the
+ real Wiimote produce. There is an unlimited amount of x, y, z combinations for any combination of
+ Roll and Pitch. But if we select a Z from the smallest of the absolute value of cos(Roll) and
+ cos (Pitch) we get the right values. */
+ // ---------
+ if (abs(cos(_Roll)) < abs(cos(_Pitch))) z = cos(_Roll); else z = cos(_Pitch);
+ /* I got these from reversing the calculation in PitchAccelerometerToDegree() in a math program
+ I don't know if we can derive these from some kind of matrix or something */
+ float x_num = 2 * tanf(0.5f * _Roll) * z;
+ float x_den = pow2f(tanf(0.5f * _Roll)) - 1;
+ x = - (x_num / x_den);
+ float y_num = 2 * tanf(0.5f * _Pitch) * z;
+ float y_den = pow2f(tanf(0.5f * _Pitch)) - 1;
+ y = - (y_num / y_den);
+ // =========================
+ }
+
+ // Multiply with the neutral of z and its g
+ float xg = g_wm.cal_g.x;
+ float yg = g_wm.cal_g.y;
+ float zg = g_wm.cal_g.z;
+ float x_zero = g_wm.cal_zero.x;
+ float y_zero = g_wm.cal_zero.y;
+ float z_zero = g_wm.cal_zero.z;
+ int ix = (int) (x_zero + xg * x);
+ int iy = (int) (y_zero + yg * y);
+ int iz = (int) (z_zero + zg * z);
+
+ // Boundaries
+ if (ix < 0) ix = 0; if (ix > 255) ix = 255;
+ if (iy < 0) iy = 0; if (iy > 255) iy = 255;
+ if (iz < 0) iz = 0; if (iz > 255) iz = 255;
+ if(g_Config.Trigger.Range.Roll != 0) _x = ix;
+ if(g_Config.Trigger.Range.Pitch != 0) _y = iy;
+ _z = iz;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Accelerometer to roll and pitch angles
+// ŻŻŻŻŻŻŻŻŻŻŻŻŻ
+float AccelerometerToG(float Current, float Neutral, float G)
+{
+ float _G = (Current - Neutral) / G;
+ return _G;
+}
+
+void PitchAccelerometerToDegree(u8 _x, u8 _y, u8 _z, int &_Roll, int &_Pitch, int &_RollAdj, int &_PitchAdj)
+{
+ // Definitions
+ float Roll = 0, Pitch = 0;
+
+ // Calculate how many g we are from the neutral
+ float x = AccelerometerToG((float)_x, (float)g_wm.cal_zero.x, (float)g_wm.cal_g.x);
+ float y = AccelerometerToG((float)_y, (float)g_wm.cal_zero.y, (float)g_wm.cal_g.y);
+ float z = AccelerometerToG((float)_z, (float)g_wm.cal_zero.z, (float)g_wm.cal_g.z);
+
+ // If it is over 1g then it is probably accelerating and may not reliable
+ //if (abs(accel->x - ac->cal_zero.x) <= ac->cal_g.x)
+ {
+ // Calculate the degree
+ Roll = InputCommon::Rad2Deg(atan2(x, z));
+ }
+
+ //if (abs(_y - g_wm.cal_zero.y) <= g_wm.cal_g.y)
+ {
+ // Calculate the degree
+ Pitch = InputCommon::Rad2Deg(atan2(y, z));
+ }
+
+ _Roll = (int)Roll;
+ _Pitch = (int)Pitch;
+
+ /* Don't allow forces bigger than 1g */
+ if (x < -1.0) x = -1.0; else if (x > 1.0) x = 1.0;
+ if (y < -1.0) y = -1.0; else if (y > 1.0) y = 1.0;
+ if (z < -1.0) z = -1.0; else if (z > 1.0) z = 1.0;
+ Roll = InputCommon::Rad2Deg(atan2(x, z));
+ Pitch = InputCommon::Rad2Deg(atan2(y, z));
+
+ _RollAdj = (int)Roll;
+ _PitchAdj = (int)Pitch;
+}
+
+
+
+//******************************************************************************
+// IR data functions
+//******************************************************************************
+
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Calculate dot positions from the basic 10 byte IR data
+// ŻŻŻŻŻŻŻŻŻŻŻŻŻ
+void IRData2DotsBasic(u8 *Data)
+{
+ struct SDot* Dot = g_Wm.IR.Dot;
+
+ Dot[0].Rx = 1023 - (Data[0] | ((Data[2] & 0x30) << 4));
+ Dot[0].Ry = Data[1] | ((Data[2] & 0xc0) << 2);
+
+ Dot[1].Rx = 1023 - (Data[3] | ((Data[2] & 0x03) << 8));
+ Dot[1].Ry = Data[4] | ((Data[2] & 0x0c) << 6);
+
+ Dot[2].Rx = 1023 - (Data[5] | ((Data[7] & 0x30) << 4));
+ Dot[2].Ry = Data[6] | ((Data[7] & 0xc0) << 2);
+
+ Dot[3].Rx = 1023 - (Data[8] | ((Data[7] & 0x03) << 8));
+ Dot[3].Ry = Data[9] | ((Data[7] & 0x0c) << 6);
+
+ /* set each IR spot to visible if spot is in range */
+ for (int i = 0; i < 4; ++i)
+ {
+ if (Dot[i].Ry == 1023)
+ {
+ Dot[i].Visible = 0;
+ }
+ else
+ {
+ Dot[i].Visible = 1;
+ Dot[i].Size = 0; /* since we don't know the size, set it as 0 */
+ }
+
+ // For now we let our virtual resolution be the same as the default one
+ Dot[i].X = Dot[i].Rx; Dot[i].Y = Dot[i].Ry;
+ }
+
+ // Calculate the other values
+ ReorderIRDots();
+ IRData2Distance();
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Calculate dot positions from the extented 12 byte IR data
+// ŻŻŻŻŻŻŻŻŻŻŻŻŻ
+void IRData2Dots(u8 *Data)
+{
+ struct SDot* Dot = g_Wm.IR.Dot;
+
+ for (int i = 0; i < 4; ++i)
+ {
+ //Console::Print("Rx: %i\n", Dot[i].Rx);
+
+ Dot[i].Rx = 1023 - (Data[3*i] | ((Data[(3*i)+2] & 0x30) << 4));
+ Dot[i].Ry = Data[(3*i)+1] | ((Data[(3*i)+2] & 0xc0) << 2);
+
+ Dot[i].Size = Data[(3*i)+2] & 0x0f;
+
+ /* if in range set to visible */
+ if (Dot[i].Ry == 1023)
+ Dot[i].Visible = false;
+ else
+ Dot[i].Visible = true;
+
+ //Console::Print("Rx: %i\n", Dot[i].Rx);
+
+ // For now we let our virtual resolution be the same as the default one
+ Dot[i].X = Dot[i].Rx; Dot[i].Y = Dot[i].Ry;
+ }
+
+ // Calculate the other values
+ ReorderIRDots();
+ IRData2Distance();
+}
+////////////////////////////////
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Reorder the IR dots according to their x-axis value
+// ŻŻŻŻŻŻŻŻŻŻŻŻŻ
+void ReorderIRDots()
+{
+ // Create a shortcut
+ struct SDot* Dot = g_Wm.IR.Dot;
+
+ // Variables
+ int i, j, order;
+
+ // Reset the dot ordering to zero
+ for (i = 0; i < 4; ++i)
+ Dot[i].Order = 0;
+
+ for (order = 1; order < 5; ++order)
+ {
+ i = 0;
+
+ //
+ for (; !Dot[i].Visible || Dot[i].Order; ++i)
+ if (i > 4) return;
+
+ //
+ for (j = 0; j < 4; ++j)
+ {
+ if (Dot[j].Visible && !Dot[j].Order && (Dot[j].X < Dot[i].X))
+ i = j;
+ }
+
+ Dot[i].Order = order;
+ }
+}
+////////////////////////////////
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Calculate dot positions from the extented 12 byte IR data
+// ŻŻŻŻŻŻŻŻŻŻŻŻŻ
+void IRData2Distance()
+{
+ // Create a shortcut
+ struct SDot* Dot = g_Wm.IR.Dot;
+
+ // Make these ones global
+ int i1, i2;
+
+ for (i1 = 0; i1 < 4; ++i1)
+ if (Dot[i1].Visible) break;
+
+ // Only one dot was visible, we can not calculate the distance
+ if (i1 == 4) { g_Wm.IR.Distance = 0; return; }
+
+ // Look at the next dot
+ for (i2 = i1 + 1; i2 < 4; ++i2)
+ if (Dot[i2].Visible) break;
+
+ // Only one dot was visible, we can not calculate the distance
+ if (i2 == 4) { g_Wm.IR.Distance = 0; return; }
+
+ /* For the emulated Wiimote the y distance is always zero so then the distance is the
+ simple distance between the x dots, i.e. the sensor bar width */
+ int xd = Dot[i2].X - Dot[i1].X;
+ int yd = Dot[i2].Y - Dot[i1].Y;
+
+ // Save the distance
+ g_Wm.IR.Distance = (int)sqrt((float)(xd*xd) + (float)(yd*yd));
+}
+////////////////////////////////
+
+
+//******************************************************************************
+// Classic Controller functions
+//******************************************************************************
+
+std::string CCData2Values(u8 *Data)
+{
+ return StringFromFormat(
+ "Tl:%03i Tr:%03i Lx:%03i Ly:%03i Rx:%03i Ry:%03i",
+ (((Data[2] & 0x60) >> 2) | ((Data[3] & 0xe0) >> 5)),
+ (Data[3] & 0x1f),
+ (Data[0] & 0x3f),
+ (Data[1] & 0x3f),
+ ((Data[0] & 0xc0) >> 3) | ((Data[1] & 0xc0) >> 5) | ((Data[2] & 0x80) >> 7),
+ (Data[2] & 0x1f));
+}
+
+} // WiiMoteEmu
\ No newline at end of file
diff --git a/Source/Plugins/Plugin_Wiimote-testing/Src/EmuMain.cpp b/Source/Plugins/Plugin_Wiimote-testing/Src/EmuMain.cpp
new file mode 100644
index 0000000000..229e26a618
--- /dev/null
+++ b/Source/Plugins/Plugin_Wiimote-testing/Src/EmuMain.cpp
@@ -0,0 +1,757 @@
+// Copyright (C) 2003-2008 Dolphin Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official SVN repository and contact information can be found at
+// http://code.google.com/p/dolphin-emu/
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Includes
+// ŻŻŻŻŻŻŻŻŻŻŻŻŻ
+#include
+#include
+
+#include "../../../Core/InputCommon/Src/SDL.h" // Core
+#include "../../../Core/InputCommon/Src/XInput.h"
+
+#include "Common.h" // Common
+#include "StringUtil.h" // for ArrayToString()
+#include "IniFile.h"
+#include "pluginspecs_wiimote.h"
+
+#include "EmuDefinitions.h" // Local
+#include "main.h"
+#include "wiimote_hid.h"
+#include "EmuSubroutines.h"
+#include "EmuMain.h"
+#include "Encryption.h" // for extension encryption
+#include "Logging.h" // for startConsoleWin, Console::Print, GetConsoleHwnd
+#include "Config.h" // for g_Config
+////////////////////////////////////
+extern SWiimoteInitialize g_WiimoteInitialize;
+
+namespace WiiMoteEmu
+{
+
+// ===================================================
+/* Bit shift conversions */
+// -------------
+u32 convert24bit(const u8* src) {
+ return (src[0] << 16) | (src[1] << 8) | src[2];
+}
+
+u16 convert16bit(const u8* src) {
+ return (src[0] << 8) | src[1];
+}
+// ==============
+
+
+// ===================================================
+/* Calibrate the mouse position to the emulation window. g_WiimoteInitialize.hWnd is the rendering window handle. */
+// ----------------
+void GetMousePos(float& x, float& y)
+{
+#ifdef _WIN32
+ POINT point;
+ // Get the cursor position for the entire screen
+ GetCursorPos(&point);
+ // Get the cursor position relative to the upper left corner of the rendering window
+ ScreenToClient(g_WiimoteInitialize.hWnd, &point);
+
+ // Get the size of the rendering window. (In my case Rect.top and Rect.left was zero.)
+ RECT Rect;
+ GetClientRect(g_WiimoteInitialize.hWnd, &Rect);
+ // Width and height is the size of the rendering window
+ float WinWidth = (float)(Rect.right - Rect.left);
+ float WinHeight = (float)(Rect.bottom - Rect.top);
+ float XOffset = 0, YOffset = 0;
+ float PictureWidth = WinWidth, PictureHeight = WinHeight;
+
+ // -----------------------------------------------------------------------
+ /* Calculate the actual picture size and location */
+ // Output: PictureWidth, PictureHeight, XOffset, YOffset
+ // ------------------
+ if (g_Config.bKeepAR43 || g_Config.bKeepAR169)
+ {
+ // The rendering window aspect ratio as a proportion of the 4:3 or 16:9 ratio
+ float Ratio = WinWidth / WinHeight / (g_Config.bKeepAR43 ? (4.0f / 3.0f) : (16.0f / 9.0f));
+
+ // Check if height or width is the limiting factor. If ratio > 1 the picture is to wide and have to limit the width.
+ if (Ratio > 1)
+ {
+ // ------------------------------------------------
+ // Calculate the new width and height for glViewport, this is not the actual size of either the picture or the screen
+ // ----------------
+ PictureWidth = WinWidth / Ratio;
+ // --------------------
+
+ // ------------------------------------------------
+ // Calculate the new X offset
+ // ----------------
+ // Move the left of the picture to the middle of the screen
+ XOffset = XOffset + WinWidth / 2.0f;
+ // Then remove half the picture height to move it to the horizontal center
+ XOffset = XOffset - PictureWidth / 2.0f;
+ // --------------------
+ }
+ // The window is to high, we have to limit the height
+ else
+ {
+ // ------------------------------------------------
+ // Calculate the new width and height for glViewport, this is not the actual size of either the picture or the screen
+ // ----------------
+ // Invert the ratio to make it > 1
+ Ratio = 1.0f / Ratio;
+ PictureHeight = WinHeight / Ratio;
+ // --------------------
+
+ // ------------------------------------------------
+ // Calculate the new Y offset
+ // ----------------
+ // Move the top of the picture to the middle of the screen
+ YOffset = YOffset + WinHeight / 2.0f;
+ // Then remove half the picture height to move it to the vertical center
+ YOffset = YOffset - PictureHeight / 2.0f;
+ // --------------------
+ }
+ // Logging
+ /*
+// Console::ClearScreen();
+ INFO_LOG(CONSOLE, "Screen Width:%4.0f Height:%4.0f Ratio:%1.2f\n", WinWidth, WinHeight, Ratio);
+ INFO_LOG(CONSOLE, "Picture Width:%4.1f Height:%4.1f YOffset:%4.0f XOffset:%4.0f\n", PictureWidth, PictureHeight, YOffset, XOffset);
+ INFO_LOG(CONSOLE, "----------------------------------------------------------------\n");
+ */
+ }
+ // -------------------------------------
+
+ // -----------------------------------------------------------------------
+ /* Crop the picture from 4:3 to 5:4 or from 16:9 to 16:10. */
+ // Output: PictureWidth, PictureHeight, XOffset, YOffset
+ // ------------------
+ if ((g_Config.bKeepAR43 || g_Config.bKeepAR169) && g_Config.bCrop)
+ {
+ float Ratio = g_Config.bKeepAR43 ? ((4.0f / 3.0f) / (5.0f / 4.0f)) : (((16.0f / 9.0f) / (16.0f / 10.0f)));
+
+ // The width and height we will add (calculate this before PictureWidth and PictureHeight is adjusted)
+ float IncreasedWidth = (Ratio - 1.0f) * PictureWidth;
+ float IncreasedHeight = (Ratio - 1.0f) * PictureHeight;
+
+ // The new width and height
+ PictureWidth = PictureWidth * Ratio;
+ PictureHeight = PictureHeight * Ratio;
+
+ // Adjust the X and Y offset
+ XOffset = float(XOffset - (IncreasedWidth / 2.0));
+ YOffset = float(YOffset - (IncreasedHeight / 2.0));
+
+ // Logging
+ /*
+ INFO_LOG(CONSOLE, "Crop Ratio:%1.2f IncrWidth:%3.0f IncrHeight:%3.0f\n", Ratio, IncreasedWidth, IncreasedHeight);
+ INFO_LOG(CONSOLE, "Picture Width:%4.1f Height:%4.1f YOffset:%4.0f XOffset:%4.0f\n", PictureWidth, PictureHeight, YOffset, XOffset);
+ INFO_LOG(CONSOLE, "----------------------------------------------------------------\n");
+ */
+ }
+ // -------------------------------------
+
+ // Return the mouse position as a fraction of one, inside the picture, with (0.0, 0.0) being the upper left corner of the picture
+ x = ((float)point.x - XOffset) / PictureWidth;
+ y = ((float)point.y - YOffset) / PictureHeight;
+
+ // ----------------------------------------------------------
+ // Logging
+ // -------------
+ /*
+ INFO_LOG(CONSOLE, "GetCursorPos: %i %i\n", point.x, point.y);
+ INFO_LOG(CONSOLE, "GetClientRect: %i %i %i %i\n", Rect.left, Rect.right, Rect.top, Rect.bottom);
+ INFO_LOG(CONSOLE, "Position X:%1.2f Y:%1.2f\n", x, y);
+ */
+ // ---------------------------
+
+#else
+ // TODO fix on linux
+ x = 0.5f;
+ y = 0.5f;
+#endif
+}
+// ==============
+
+
+// ===================================================
+/* Homebrew encryption for 16 byte zero keys. */
+// ----------------
+void CryptBuffer(u8* _buffer, u8 _size)
+{
+ for (int i=0; i<_size; i++)
+ {
+ _buffer[i] = ((_buffer[i] - 0x17) ^ 0x17) & 0xFF;
+ }
+}
+
+void WriteCrypted16(u8* _baseBlock, u16 _address, u16 _value)
+{
+ u16 cryptedValue = _value;
+ CryptBuffer((u8*)&cryptedValue, sizeof(u16));
+
+ *(u16*)(_baseBlock + _address) = cryptedValue;
+ //PanicAlert("Converted %04x to %04x", _value, cryptedValue);
+}
+// ================
+
+
+// ===================================================
+/* Calculate Extenstion Regisister Calibration Checksum */
+// This function is not currently used, it's just here to show how the values in EmuDefinitions.h are calculated.
+// ----------------
+void GetCalibrationChecksum()
+{
+ u8 sum = 0;
+ for (int i = 0; i < sizeof(nunchuck_calibration) - 2; i++)
+ sum += nunchuck_calibration[i];
+ u8 Check1 = sum + 0x55;
+ u8 Check2 = sum + 0xaa;
+ INFO_LOG(CONSOLE, "0x%02x 0x%02x", Check1, Check2);
+}
+// ================
+
+
+// ===================================================
+/* Load pre-recorded movements */
+// ----------------
+void LoadRecordedMovements()
+{
+ INFO_LOG(CONSOLE, "LoadRecordedMovements()\n");
+
+ IniFile file;
+ file.Load(FULL_CONFIG_DIR "WiimoteMovement.ini");
+
+ for(int i = 0; i < RECORDING_ROWS; i++)
+ {
+ // Logging
+ //INFO_LOG(CONSOLE, "Recording%i ", i + 1);
+
+ // Temporary storage
+ int iTmp;
+ std::string STmp;
+
+ // First clear the list
+ VRecording.at(i).Recording.clear();
+
+ // Get row name
+ std::string SaveName = StringFromFormat("Recording%i", i + 1);
+
+ // Get movement
+ std::string TmpMovement; file.Get(SaveName.c_str(), "Movement", &TmpMovement, "");
+
+ // Get IR
+ std::string TmpIR; file.Get(SaveName.c_str(), "IR", &TmpIR, "");
+
+ // Get time
+ std::string TmpTime; file.Get(SaveName.c_str(), "Time", &TmpTime, "");
+
+ // Get IR bytes
+ int TmpIRBytes; file.Get(SaveName.c_str(), "IRBytes", &TmpIRBytes, 0);
+ VRecording.at(i).IRBytes = TmpIRBytes;
+
+ SRecording Tmp;
+ for (int j = 0, k = 0, l = 0; (u32)j < TmpMovement.length(); j+=13)
+ {
+ // Skip blank savings
+ if (TmpMovement.length() < 3) continue;
+
+ // Avoid going to far, this can only happen with modified ini files, but we check for it anyway
+ if (TmpMovement.length() < (u32)j + 12) continue;
+
+ // Skip old style recordings
+ if (TmpMovement.substr(j, 1) != "-" && TmpMovement.substr(j, 1) != "+") continue;
+
+ std::string StrX = TmpMovement.substr(j, 4);
+ std::string StrY = TmpMovement.substr(j + 4, 4);
+ std::string StrZ = TmpMovement.substr(j + 8, 4);
+ Tmp.x = atoi(StrX.c_str());
+ Tmp.y = atoi(StrY.c_str());
+ Tmp.z = atoi(StrZ.c_str());
+
+ // ---------------------------------
+ // Go to next set of IR values
+ // ---------
+ // If there is no IR data saving we fill the array with zeroes. This should only be able to occur from manual ini editing
+ // but we check for it anyway
+ if (TmpIRBytes == 0) for(int i = 0; i < 12; i++) Tmp.IR[i] = 0;
+ for(int ii = 0; ii < TmpIRBytes; ii++)
+ {
+ if(TmpIR.length() < (u32)(k + i + TmpIRBytes)) continue; // Safety check
+ std::string TmpStr = TmpIR.substr(k + ii*2, 2);
+ u32 TmpU32;
+ AsciiToHex(TmpStr.c_str(), TmpU32);
+ Tmp.IR[ii] = (u8)TmpU32;
+ }
+ if (TmpIRBytes == 10) k += (10*2 + 1); else k += (12*2 + 1);
+ // ---------------------
+
+ // Go to next set of time values
+ double Time = (double)atoi(TmpTime.substr(l, 5).c_str());
+ Tmp.Time = (double)(Time/1000);
+ l += 6;
+
+ // Save the values
+ VRecording.at(i).Recording.push_back(Tmp);
+
+ // ---------------------------------
+ // Log results
+ // ---------
+ /*INFO_LOG(CONSOLE, "Time:%f\n", Tmp.Time);
+ std::string TmpIRLog = ArrayToString(Tmp.IR, TmpIRBytes, 0, 30);
+ INFO_LOG(CONSOLE, "IR: %s\n", TmpIRLog.c_str());
+ INFO_LOG(CONSOLE, "\n");*/
+ }
+
+ // Get HotKey
+ file.Get(SaveName.c_str(), "HotKeySwitch", &iTmp, 3); VRecording.at(i).HotKeySwitch = iTmp;
+ file.Get(SaveName.c_str(), "HotKeyWiimote", &iTmp, 10); VRecording.at(i).HotKeyWiimote = iTmp;
+ file.Get(SaveName.c_str(), "HotKeyNunchuck", &iTmp, 10); VRecording.at(i).HotKeyNunchuck = iTmp;
+ file.Get(SaveName.c_str(), "HotKeyIR", &iTmp, 10); VRecording.at(i).HotKeyIR = iTmp;
+
+ // Get Recording speed
+ int TmpPlaybackSpeed; file.Get(SaveName.c_str(), "PlaybackSpeed", &TmpPlaybackSpeed, -1);
+ VRecording.at(i).PlaybackSpeed = TmpPlaybackSpeed;
+
+ // ---------------------------------
+ // Logging
+ // ---------
+ /*std::string TmpIRLog;
+ if(TmpIRBytes > 0 && VRecording.size() > i)
+ TmpIRLog = ArrayToString(VRecording.at(i).Recording.at(0).IR, TmpIRBytes, 0, 30);
+ else
+ TmpIRLog = "";
+
+ INFO_LOG(CONSOLE, "Size:%i HotKey:%i PlSpeed:%i IR:%s X:%i Y:%i Z:%i\n",
+ VRecording.at(i).Recording.size(), VRecording.at(i).HotKeyWiimote, VRecording.at(i).PlaybackSpeed,
+ TmpIRLog.c_str(),
+ VRecording.at(i).Recording.at(0).x, VRecording.at(i).Recording.at(0).y, VRecording.at(i).Recording.at(0).z
+ );*/
+ // ---------------------
+ }
+}
+// ================
+
+// Update the accelerometer neutral values
+void UpdateEeprom()
+{
+ g_wm.cal_zero.x = g_Eeprom[22];
+ g_wm.cal_zero.y = g_Eeprom[23];
+ g_wm.cal_zero.z = g_Eeprom[24];
+ g_wm.cal_g.x = g_Eeprom[26] - g_Eeprom[22];
+ g_wm.cal_g.y = g_Eeprom[27] - g_Eeprom[24];
+ g_wm.cal_g.z = g_Eeprom[28] - g_Eeprom[24];
+
+ INFO_LOG(CONSOLE, "\nUpdateEeprom: %i %i %i\n",
+ WiiMoteEmu::g_Eeprom[22], WiiMoteEmu::g_Eeprom[23], WiiMoteEmu::g_Eeprom[28]);
+
+ if(g_Config.bNunchuckConnected)
+ {
+ g_nu.cal_zero.x = g_RegExt[0x20];
+ g_nu.cal_zero.y = g_RegExt[0x21];
+ g_nu.cal_zero.z = g_RegExt[0x22];
+ g_nu.cal_g.x = g_RegExt[0x24] - g_RegExt[0x20];
+ g_nu.cal_g.y = g_RegExt[0x25] - g_RegExt[0x21];
+ g_nu.cal_g.z = g_RegExt[0x26] - g_RegExt[0x22];
+ g_nu.jx.max = g_RegExt[0x28];
+ g_nu.jx.min = g_RegExt[0x29];
+ g_nu.jx.center = g_RegExt[0x2a];
+ g_nu.jy.max = g_RegExt[0x2b];
+ g_nu.jy.min = g_RegExt[0x2c];
+ g_nu.jy.center = g_RegExt[0x2d];
+
+ INFO_LOG(CONSOLE, "UpdateNunchuck: %i %i %i %i %i\n\n",
+ WiiMoteEmu::g_RegExt[0x2a], WiiMoteEmu::g_RegExt[0x2d],
+ WiiMoteEmu::g_RegExt[0x20], WiiMoteEmu::g_RegExt[0x21], WiiMoteEmu::g_RegExt[0x26]);
+ }
+ else if(g_Config.bClassicControllerConnected)
+ {
+ g_cc.Lx.max = g_RegExt[0x20];
+ g_cc.Lx.min = g_RegExt[0x21];
+ g_cc.Lx.center = g_RegExt[0x22];
+ g_cc.Ly.max = g_RegExt[0x23];
+ g_cc.Ly.min = g_RegExt[0x24];
+ g_cc.Ly.center = g_RegExt[0x25];
+
+ g_cc.Rx.max = g_RegExt[0x26];
+ g_cc.Rx.min = g_RegExt[0x27];
+ g_cc.Rx.center = g_RegExt[0x28];
+ g_cc.Ry.max = g_RegExt[0x29];
+ g_cc.Ry.min = g_RegExt[0x2a];
+ g_cc.Ry.center = g_RegExt[0x2b];
+
+ g_cc.Tl.neutral = g_RegExt[0x2c];
+ g_cc.Tr.neutral = g_RegExt[0x2d];
+
+ INFO_LOG(CONSOLE, "UpdateCC: %i %i %i %i %i\n\n",
+ WiiMoteEmu::g_RegExt[0x2a], WiiMoteEmu::g_RegExt[0x2d],
+ WiiMoteEmu::g_RegExt[0x20], WiiMoteEmu::g_RegExt[0x21], WiiMoteEmu::g_RegExt[0x26]);
+ }
+
+
+}
+
+// Calculate checksum for the nunchuck calibration. The last two bytes.
+void ExtensionChecksum(u8 * Calibration)
+{
+ u8 sum = 0; u8 Byte15, Byte16;
+ for (int i = 0; i < sizeof(Calibration) - 2; i++)
+ {
+ sum += Calibration[i];
+ printf("Plus 0x%02x\n", Calibration[i]);
+ }
+ Byte15 = sum + 0x55; // Byte 15
+ Byte16 = sum + 0xaa; // Byte 16
+}
+
+// Set initial valuesm this done both in Init and Shutdown
+void ResetVariables()
+{
+ u8 g_Leds = 0x0; // 4 bits
+ u8 g_Speaker = 0x0; // 1 = on
+ u8 g_SpeakerVoice = 0x0; // 1 = on
+ u8 g_IR = 0x0; // 1 = on
+
+ g_ReportingMode = 0;
+ g_ReportingChannel = 0;
+ g_Encryption = false;
+
+ // Set default recording values
+#if defined(HAVE_WX) && HAVE_WX
+ for (int i = 0; i < 3; i++)
+ {
+ g_RecordingPlaying[i] = -1;
+ g_RecordingCounter[i] = 0;
+ g_RecordingPoint[i] = 0;
+ g_RecordingStart[i] = 0;
+ g_RecordingCurrentTime[i] = 0;
+ }
+#endif
+ g_EmulatedWiiMoteInitialized = false;
+}
+
+// Update the extension calibration values with our default values
+void SetDefaultExtensionRegistry()
+{
+ // Copy extension id and calibration to its register
+ if(g_Config.bNunchuckConnected)
+ {
+ memcpy(g_RegExt + 0x20, nunchuck_calibration, sizeof(nunchuck_calibration));
+ memcpy(g_RegExt + 0x30, nunchuck_calibration, sizeof(nunchuck_calibration));
+ memcpy(g_RegExt + 0xfa, nunchuck_id, sizeof(nunchuck_id));
+ }
+ else if(g_Config.bClassicControllerConnected)
+ {
+ memcpy(g_RegExt + 0x20, classic_calibration, sizeof(classic_calibration));
+ memcpy(g_RegExt + 0x30, classic_calibration, sizeof(classic_calibration));
+ memcpy(g_RegExt + 0xfa, classic_id, sizeof(classic_id));
+ }
+
+ INFO_LOG(CONSOLE, "\nSetDefaultExtensionRegistry()\n\n");
+
+ UpdateEeprom();
+}
+
+
+// ===================================================
+/* Write initial values to Eeprom and registers. */
+// ----------------
+void Initialize()
+{
+ if (g_EmulatedWiiMoteInitialized) return;
+
+ // Reset variables
+ ResetVariables();
+
+ // Write default Eeprom data to g_Eeprom[], this may be overwritten by WiiMoteReal::Initialize()
+ // after this function.
+ memset(g_Eeprom, 0, WIIMOTE_EEPROM_SIZE);
+ memcpy(g_Eeprom, EepromData_0, sizeof(EepromData_0));
+ memcpy(g_Eeprom + 0x16D0, EepromData_16D0, sizeof(EepromData_16D0));
+
+ /* Populate joyinfo for all attached devices and do g_Config.Load() if the configuration window is
+ not already open, if it's already open we continue with the settings we have */
+ if(!g_FrameOpen)
+ {
+ Search_Devices(joyinfo, NumPads, NumGoodPads);
+ }
+
+ // Copy extension id and calibration to its register, g_Config.Load() is needed before this
+ SetDefaultExtensionRegistry();
+
+ // The emulated Wiimote is initialized
+ g_EmulatedWiiMoteInitialized = true;
+
+ // Load pre-recorded movements
+ LoadRecordedMovements();
+
+ /* The Nuncheck extension ID for homebrew applications that use the zero key. This writes 0x0000
+ in encrypted form (0xfefe) to 0xfe in the extension register. */
+ //WriteCrypted16(g_RegExt, 0xfe, 0x0000); // Fully inserted Nunchuk
+
+ // I forgot what these were for? Is this the zero key encrypted 0xa420?
+ // g_RegExt[0xfd] = 0x1e;
+ // g_RegExt[0xfc] = 0x9a;
+}
+// ================
+
+
+void DoState(void* ptr, int mode)
+{
+ //TODO: implement
+}
+
+/* This is not needed if we call FreeLibrary() when we stop a game, but if it's not called we need to reset
+ these variables. */
+void Shutdown(void)
+{
+ INFO_LOG(CONSOLE, "ShutDown\n");
+
+ ResetVariables();
+
+ /* Close all devices carefully. We must check that we are not accessing any undefined
+ vector elements or any bad devices */
+ for (int i = 0; i < 1; i++)
+ {
+ if (PadMapping[i].enabled && joyinfo.size() > (u32)PadMapping[i].ID)
+ if (joyinfo.at(PadMapping[i].ID).Good)
+ {
+ INFO_LOG(CONSOLE, "ShutDown: %i\n", PadState[i].joy);
+ /* SDL_JoystickClose() crashes for some reason so I avoid this for now, SDL_Quit() should
+ close the pads to I think */
+ //if(SDL_JoystickOpened(PadMapping[i].ID)) SDL_JoystickClose(PadState[i].joy);
+ //PadState[i].joy = NULL;
+ }
+ }
+
+ // Clear the physical device info
+ joyinfo.clear();
+ NumPads = 0;
+ NumGoodPads = 0;
+
+ // Finally close SDL
+ if (SDL_WasInit(0)) SDL_Quit();
+}
+
+
+// ===================================================
+/* An ack delay of 1 was not small enough, but 2 seemed to work, that was about between 20 ms and
+ 100 ms in my case in Zelda - TP. You may have to increase this value for other things to work, for
+ example in the wpad demo I had to set it to at least 3 for the Sound to be able to turned on (I have
+ an update rate of around 150 fps in the wpad demo) */
+// ----------------
+void CreateAckDelay(u8 _ChannelID, u16 _ReportID)
+{
+ // Settings
+ int GlobalDelay = 2;
+
+ // Queue an acknowledgment
+ wm_ackdelay Tmp;
+ Tmp.Delay = GlobalDelay;
+ Tmp.ChannelID = _ChannelID;
+ Tmp.ReportID = (u8)_ReportID;
+ AckDelay.push_back(Tmp);
+}
+
+
+void CheckAckDelay()
+{
+ for (int i = 0; i < (int)AckDelay.size(); i++)
+ {
+ // See if there are any acks to send
+ if (AckDelay.at(i).Delay >= 0)
+ {
+ if(AckDelay.at(i).Delay == 0)
+ {
+ WmSendAck(AckDelay.at(i).ChannelID, AckDelay.at(i).ReportID, 0);
+ AckDelay.erase(AckDelay.begin() + i);
+ continue;
+ }
+ AckDelay.at(i).Delay--;
+
+ //INFO_LOG(CONSOLE, "%i 0x%04x 0x%02x", i, AckDelay.at(i).ChannelID, AckDelay.at(i).ReportID);
+ }
+ }
+}
+// ================
+
+
+// ===================================================
+/* This function produce Wiimote Input, i.e. reports from the Wiimote in response
+ to Output from the Wii. */
+// ----------------
+void InterruptChannel(u16 _channelID, const void* _pData, u32 _Size)
+{
+ //INFO_LOG(CONSOLE, "Emu InterruptChannel\n");
+
+ DEBUG_LOG(WII_IPC_WIIMOTE, "=============================================================");
+ DEBUG_LOG(WII_IPC_WIIMOTE, "Wiimote_Input");
+ const u8* data = (const u8*)_pData;
+
+ /* Debugging. We have not yet decided how much of 'data' we will use, it's not determined
+ by sizeof(data). We have to determine it by looking at the data cases. */
+ InterruptDebugging(true, data);
+
+ hid_packet* hidp = (hid_packet*) data;
+ switch(hidp->type)
+ {
+ case HID_TYPE_DATA:
+ {
+ switch(hidp->param)
+ {
+ case HID_PARAM_OUTPUT:
+ {
+ wm_report* sr = (wm_report*)hidp->data;
+ HidOutputReport(_channelID, sr);
+
+ /* This is the 0x22 answer to all Inputs. In most games it didn't matter
+ if it was written before or after HidOutputReport(), but Wii Sports
+ and Mario Galaxy would stop working if it was placed before
+ HidOutputReport(). Zelda - TP is even more sensitive and require
+ a delay after the Input for the Nunchuck to work. It seemed to be
+ enough to delay only the Nunchuck registry reads and writes but
+ for now I'm delaying all inputs. Both for status changes and Eeprom
+ and registry reads and writes. */
+
+ // There are no 0x22 replys to these report from the real wiimote from what I could see
+ // Report 0x10 that seems to be only used for rumble, and we don't need to answer that,
+ // also if we do *we should update the 0x22 to have the core keys* otherwise the game will
+ // think we release the key every time it rumbles
+ if(!(data[1] == WM_READ_DATA && data[2] == 0x00)
+ && !(data[1] == WM_REQUEST_STATUS)
+ && !(data[1] == WM_WRITE_SPEAKER_DATA)
+ && !(data[1] == WM_RUMBLE))
+ if (!g_Config.bUseRealWiimote || !g_RealWiiMotePresent) CreateAckDelay((u8)_channelID, (u16)sr->channel);
+ }
+ break;
+
+ default:
+ ERROR_LOG(WII_IPC_WIIMOTE, "HidInput: HID_TYPE_DATA - param 0x%02x", hidp->type, hidp->param);
+ PanicAlert("HidInput: HID_TYPE_DATA - param 0x%02x", hidp->type, hidp->param);
+ break;
+ }
+ }
+ break;
+
+ default:
+ ERROR_LOG(WII_IPC_WIIMOTE,"HidInput: Unknown type 0x%02x and param 0x%02x", hidp->type, hidp->param);
+ PanicAlert("HidInput: Unknown type 0x%02x and param 0x%02x", hidp->type, hidp->param);
+ break;
+ }
+ DEBUG_LOG(WII_IPC_WIIMOTE, "=============================================================");
+}
+
+
+void ControlChannel(u16 _channelID, const void* _pData, u32 _Size)
+{
+ //INFO_LOG(CONSOLE, "Emu ControlChannel\n");
+
+ const u8* data = (const u8*)_pData;
+ // Dump raw data
+ {
+ INFO_LOG(WII_IPC_WIIMOTE, "Wiimote_ControlChannel");
+ std::string Temp = ArrayToString(data, 0, _Size);
+#if defined(HAVE_WX) && HAVE_WX
+ INFO_LOG(CONSOLE, "\n%s: ControlChannel: %s\n", Tm().c_str(), Temp.c_str());
+#endif
+ DEBUG_LOG(WII_IPC_WIIMOTE, " Data: %s", Temp.c_str());
+ }
+
+ hid_packet* hidp = (hid_packet*) data;
+ switch(hidp->type)
+ {
+ case HID_TYPE_HANDSHAKE:
+ if (hidp->param == HID_PARAM_INPUT)
+ {
+ ERROR_LOG(WII_IPC_WIIMOTE, "HID_TYPE_HANDSHAKE - HID_PARAM_INPUT");
+ PanicAlert("HID_TYPE_HANDSHAKE - HID_PARAM_INPUT");
+ }
+ else
+ {
+ ERROR_LOG(WII_IPC_WIIMOTE, "HID_TYPE_HANDSHAKE - HID_PARAM_OUTPUT");
+ PanicAlert("HID_TYPE_HANDSHAKE - HID_PARAM_OUTPUT");
+ }
+ break;
+
+ case HID_TYPE_SET_REPORT:
+ if (hidp->param == HID_PARAM_INPUT)
+ {
+ ERROR_LOG(WII_IPC_WIIMOTE, "HID_TYPE_SET_REPORT input");
+ PanicAlert("HID_TYPE_SET_REPORT input");
+ }
+ else
+ {
+ HidOutputReport(_channelID, (wm_report*)hidp->data);
+
+ // Return handshake
+ u8 handshake = 0;
+ g_WiimoteInitialize.pWiimoteInput(_channelID, &handshake, 1);
+ }
+ break;
+
+ case HID_TYPE_DATA:
+ ERROR_LOG(WII_IPC_WIIMOTE, "HID_TYPE_DATA %s", hidp->type, hidp->param == HID_PARAM_INPUT ? "input" : "output");
+ PanicAlert("HID_TYPE_DATA %s", hidp->type, hidp->param == HID_PARAM_INPUT ? "input" : "output");
+ break;
+
+ default:
+ ERROR_LOG(WII_IPC_WIIMOTE, "HidControlChannel: Unknown type %x and param %x", hidp->type, hidp->param);
+ PanicAlert("HidControlChannel: Unknown type %x and param %x", hidp->type, hidp->param);
+ break;
+ }
+
+}
+
+
+// ===================================================
+/* This is called from Wiimote_Update(). See SystemTimers.cpp for a documentation. I'm
+ not sure exactly how often this function is called but I think it's tied to the frame
+ rate of the game rather than a certain amount of times per second. */
+// ----------------
+void Update()
+{
+ //LOG(WII_IPC_WIIMOTE, "Wiimote_Update");
+ //INFO_LOG(CONSOLE, "Emu Update: %i\n", g_ReportingMode);
+
+ // Check if the pad state should be updated
+ if ((g_Config.Trigger.Type == g_Config.Trigger.TRIGGER || g_Config.Trigger.Type == g_Config.Trigger.ANALOG1 || g_Config.Trigger.Type == g_Config.Trigger.ANALOG2
+ || g_Config.Nunchuck.Type == g_Config.Nunchuck.ANALOG1 || g_Config.Nunchuck.Type == g_Config.Nunchuck.ANALOG2
+ || g_Config.ClassicController.LType == g_Config.ClassicController.ANALOG1 || g_Config.ClassicController.LType == g_Config.ClassicController.ANALOG2
+ || g_Config.ClassicController.RType == g_Config.ClassicController.ANALOG1 || g_Config.ClassicController.RType == g_Config.ClassicController.ANALOG2)
+ && NumGoodPads > 0 && joyinfo.size() > (u32)PadMapping[0].ID)
+ {
+ const int Page = 0;
+ WiiMoteEmu::GetJoyState(PadState[Page], PadMapping[Page], Page, joyinfo[PadMapping[Page].ID].NumButtons);
+ }
+
+ switch(g_ReportingMode)
+ {
+ case 0:
+ break;
+ case WM_REPORT_CORE: SendReportCore(g_ReportingChannel); break;
+ case WM_REPORT_CORE_ACCEL: SendReportCoreAccel(g_ReportingChannel); break;
+ case WM_REPORT_CORE_ACCEL_IR12: SendReportCoreAccelIr12(g_ReportingChannel); break;
+ case WM_REPORT_CORE_ACCEL_EXT16: SendReportCoreAccelExt16(g_ReportingChannel); break;
+ case WM_REPORT_CORE_ACCEL_IR10_EXT6: SendReportCoreAccelIr10Ext(g_ReportingChannel);break;
+ }
+
+ // Potentially send a delayed acknowledgement to an InterruptChannel() Output
+ CheckAckDelay();
+}
+
+
+} // end of namespace
+
diff --git a/Source/Plugins/Plugin_Wiimote-testing/Src/EmuMain.h b/Source/Plugins/Plugin_Wiimote-testing/Src/EmuMain.h
new file mode 100644
index 0000000000..ca5fea28c0
--- /dev/null
+++ b/Source/Plugins/Plugin_Wiimote-testing/Src/EmuMain.h
@@ -0,0 +1,77 @@
+// Copyright (C) 2003-2008 Dolphin Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official SVN repository and contact information can be found at
+// http://code.google.com/p/dolphin-emu/
+
+#ifndef WIIMOTE_EMU_H
+#define WIIMOTE_EMU_H
+
+
+#include
+
+#include "../../../Core/InputCommon/Src/SDL.h" // Core
+
+#include "wiimote_hid.h"
+#include "EmuDefinitions.h"
+
+namespace WiiMoteEmu
+{
+
+u32 convert24bit(const u8* src);
+u16 convert16bit(const u8* src);
+void GetMousePos(float& x, float& y);
+
+// General functions
+void Initialize();
+void DoState(void* ptr, int mode);
+void Shutdown(void);
+void InterruptChannel(u16 _channelID, const void* _pData, u32 _Size);
+void ControlChannel(u16 _channelID, const void* _pData, u32 _Size) ;
+void Update();
+
+// Recordings
+void LoadRecordedMovements();
+
+// Registers and calibration values
+void ResetVariables();
+void UpdateEeprom();
+void SetDefaultExtensionRegistry();
+
+// Gamepad
+bool Search_Devices(std::vector &_joyinfo, int &_NumPads, int &_NumGoodPads);
+void GetJoyState(InputCommon::CONTROLLER_STATE_NEW &_PadState, InputCommon::CONTROLLER_MAPPING_NEW _PadMapping, int controller, int NumButtons);
+void PadStateAdjustments(int &Lx, int &Ly, int &Rx, int &Ry, int &Tl, int &Tr);
+
+// Accelerometer
+void PitchDegreeToAccelerometer(float _Roll, float _Pitch, u8 &_x, u8 &_y, u8 &_z);
+void PitchAccelerometerToDegree(u8 _x, u8 _y, u8 _z, int &_Roll, int &_Pitch, int&, int&);
+float AccelerometerToG(float Current, float Neutral, float G);
+void TiltTest(u8 x, u8 y, u8 z);
+void Tilt(u8 &_x, u8 &_y, u8 &_z);
+void AdjustAngles(float &Roll, float &Pitch);
+
+// IR data
+void IRData2Dots(u8 *Data);
+void IRData2DotsBasic(u8 *Data);
+void ReorderIRDots();
+void IRData2Distance();
+
+// Classic Controller data
+std::string CCData2Values(u8 *Data);
+
+}; // WiiMoteEmu
+
+
+#endif
diff --git a/Source/Plugins/Plugin_Wiimote-testing/Src/EmuPad.cpp b/Source/Plugins/Plugin_Wiimote-testing/Src/EmuPad.cpp
new file mode 100644
index 0000000000..4db783bfdf
--- /dev/null
+++ b/Source/Plugins/Plugin_Wiimote-testing/Src/EmuPad.cpp
@@ -0,0 +1,195 @@
+// Copyright (C) 2003-2008 Dolphin Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official SVN repository and contact information can be found at
+// http://code.google.com/p/dolphin-emu/
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Includes
+// ŻŻŻŻŻŻŻŻŻŻŻŻŻ
+#include
+#include
+
+#include "../../../Core/InputCommon/Src/SDL.h" // Core
+#include "../../../Core/InputCommon/Src/XInput.h"
+
+#include "Common.h" // Common
+#include "StringUtil.h" // for ArrayToString()
+#include "IniFile.h"
+#include "pluginspecs_wiimote.h"
+
+#include "EmuDefinitions.h" // Local
+#include "main.h"
+#include "wiimote_hid.h"
+#include "EmuSubroutines.h"
+#include "EmuMain.h"
+#include "Encryption.h" // for extension encryption
+#include "Logging.h" // for startConsoleWin, Console::Print, GetConsoleHwnd
+#include "Config.h" // for g_Config
+////////////////////////////////////
+
+extern SWiimoteInitialize g_WiimoteInitialize;
+
+namespace WiiMoteEmu
+{
+
+// ===================================================
+// Fill joyinfo with the current connected devices
+// ----------------
+bool Search_Devices(std::vector &_joyinfo, int &_NumPads, int &_NumGoodPads)
+{
+ bool Success = InputCommon::SearchDevices(_joyinfo, _NumPads, _NumGoodPads);
+
+ // Warn the user if no gamepads are detected
+ if (_NumGoodPads == 0 && g_EmulatorRunning)
+ {
+ //PanicAlert("nJoy: No Gamepad Detected");
+ //return false;
+ }
+
+ // Load PadMapping[] etc
+ g_Config.Load();
+
+ // Update the PadState[].joy handle
+ for (int i = 0; i < 1; i++)
+ {
+ if (PadMapping[i].enabled && joyinfo.size() > (u32)PadMapping[i].ID)
+ if(joyinfo.at(PadMapping[i].ID).Good)
+ PadState[i].joy = SDL_JoystickOpen(PadMapping[i].ID);
+ }
+
+ return Success;
+}
+// ===========================
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Return adjusted input values
+// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
+void PadStateAdjustments(int &Lx, int &Ly, int &Rx, int &Ry, int &Tl, int &Tr)
+{
+ // This has to be changed if multiple Wiimotes are to be supported later
+ const int Page = 0;
+
+ // Copy all states to a local variable
+ Lx = PadState[Page].Axis.Lx;
+ Ly = PadState[Page].Axis.Ly;
+ Rx = PadState[Page].Axis.Rx;
+ Ry = PadState[Page].Axis.Ry;
+ Tl = PadState[Page].Axis.Tl;
+ Tr = PadState[Page].Axis.Tr;
+
+ // Check the circle to square option
+ if(PadMapping[Page].bCircle2Square)
+ {
+ std::vector main_xy = InputCommon::Square2Circle(Lx, Ly, Page, PadMapping[Page].SDiagonal, true);
+
+ Lx = main_xy.at(0);
+ Ly = main_xy.at(1);
+ }
+
+ // Dead zone adjustment
+ float DeadZoneLeft = (float)PadMapping[Page].DeadZoneL / 100.0f;
+ float DeadZoneRight = (float)PadMapping[Page].DeadZoneR / 100.0f;
+ if (InputCommon::IsDeadZone(DeadZoneLeft, Lx, Ly))
+ {
+ Lx = 0;
+ Ly = 0;
+ }
+ if (InputCommon::IsDeadZone(DeadZoneRight, Rx, Ry))
+ {
+ Rx = 0;
+ Ry = 0;
+ }
+
+ // Downsize the values from 0x8000 to 0x80
+ Lx = InputCommon::Pad_Convert(Lx);
+ Ly = InputCommon::Pad_Convert(Ly);
+ Rx = InputCommon::Pad_Convert(Rx);
+ Ry = InputCommon::Pad_Convert(Ry);
+ // The XInput range is already 0 to 0x80
+ if (PadMapping[Page].triggertype == InputCommon::CTL_TRIGGER_SDL)
+ {
+ Tl = InputCommon::Pad_Convert(PadState[Page].Axis.Tl);
+ Tr = InputCommon::Pad_Convert(PadState[Page].Axis.Tr);
+ }
+}
+
+////////////////////////////////////////////
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// 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(InputCommon::CONTROLLER_STATE_NEW &_PadState, InputCommon::CONTROLLER_MAPPING_NEW _PadMapping, int controller, int NumButtons)
+{
+ // Return if we have no pads
+ if (NumGoodPads == 0) return;
+
+ // 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.Lx = SDL_JoystickGetAxis(_PadState.joy, _PadMapping.Axis.Lx);
+ _PadState.Axis.Ly = SDL_JoystickGetAxis(_PadState.joy, _PadMapping.Axis.Ly);
+ _PadState.Axis.Rx = SDL_JoystickGetAxis(_PadState.joy, _PadMapping.Axis.Rx);
+ _PadState.Axis.Ry = SDL_JoystickGetAxis(_PadState.joy, _PadMapping.Axis.Ry);
+
+ // Update the analog trigger axis values
+#ifdef _WIN32
+ if (_PadMapping.triggertype == InputCommon::CTL_TRIGGER_SDL)
+ {
+#endif
+ // If we are using SDL analog triggers the buttons have to be mapped as 1000 or up, otherwise they are not used
+ // We must also check that we are not asking for a negative axis number because SDL_JoystickGetAxis() has
+ // no good way of handling that
+ if ((_PadMapping.Axis.Tl - 1000) >= 0) _PadState.Axis.Tl = SDL_JoystickGetAxis(_PadState.joy, _PadMapping.Axis.Tl - 1000);
+ if ((_PadMapping.Axis.Tr - 1000) >= 0) _PadState.Axis.Tr = SDL_JoystickGetAxis(_PadState.joy, _PadMapping.Axis.Tr - 1000);
+#ifdef _WIN32
+ }
+ else
+ {
+ _PadState.Axis.Tl = XInput::GetXI(0, _PadMapping.Axis.Tl - 1000);
+ _PadState.Axis.Tr = XInput::GetXI(0, _PadMapping.Axis.Tr - 1000);
+ }
+#endif
+
+ /* Debugging
+// Console::ClearScreen();
+ DEBUG_LOG(CONSOLE,
+ "Controller and handle: %i %i\n"
+
+ "Triggers:%i %i %i %i %i\n"
+
+ "Analog:%06i %06i \n",
+
+ controller, (int)_PadState.joy,
+
+ _PadMapping.triggertype,
+ _PadMapping.Axis.Tl, _PadMapping.Axis.Tr,
+ _PadState.Axis.Tl, _PadState.Axis.Tr,
+
+ _PadState.Axis.Lx, _PadState.Axis.Ly
+ );*/
+}
+////////////////////////////////////////////
+
+
+} // end of namespace WiiMoteEmu
+
diff --git a/Source/Plugins/Plugin_Wiimote-testing/Src/EmuSubroutines.cpp b/Source/Plugins/Plugin_Wiimote-testing/Src/EmuSubroutines.cpp
new file mode 100644
index 0000000000..f1166beade
--- /dev/null
+++ b/Source/Plugins/Plugin_Wiimote-testing/Src/EmuSubroutines.cpp
@@ -0,0 +1,607 @@
+// Copyright (C) 2003-2008 Dolphin Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official SVN repository and contact information can be found at
+// http://code.google.com/p/dolphin-emu/
+
+
+
+
+// ===================================================
+/* HID reports access guide. */
+// ----------------
+
+/* 0x10 - 0x1a Output EmuMain.cpp: HidOutputReport()
+ 0x10 - 0x14: General
+ 0x15: Status report request from the Wii
+ 0x16 and 0x17: Write and read memory or registers
+ 0x19 and 0x1a: General
+ 0x20 - 0x22 Input EmuMain.cpp: HidOutputReport() to the destination
+ 0x15 leads to a 0x20 Input report
+ 0x17 leads to a 0x21 Input report
+ 0x10 - 0x1a leads to a 0x22 Input report
+ 0x30 - 0x3f Input This file: Update() */
+
+// ================
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Includes
+// ŻŻŻŻŻŻŻŻŻŻŻŻŻ
+#include
+#include
+
+#include "Common.h" // Common
+#include "StringUtil.h"
+#include "pluginspecs_wiimote.h"
+
+#include "EmuMain.h" // Local
+#include "EmuSubroutines.h"
+#include "Logging.h" // for startConsoleWin, Console::Print, GetConsoleHwnd
+#include "Config.h" // for g_Config
+/////////////////////////////////
+
+
+extern SWiimoteInitialize g_WiimoteInitialize;
+
+namespace WiiMoteEmu
+{
+
+//******************************************************************************
+// Subroutines
+//******************************************************************************
+
+
+// ===================================================
+/* Here we process the Output Reports that the Wii sends. Our response will be an Input Report
+ back to the Wii. Input and Output is from the Wii's perspective, Output means data to
+ the Wiimote (from the Wii), Input means data from the Wiimote.
+
+ The call browser:
+
+ 1. Wiimote_InterruptChannel > InterruptChannel > HidOutputReport
+ 2. Wiimote_ControlChannel > ControlChannel > HidOutputReport
+
+ The IR lights and speaker enable/disable and mute/unmute values are
+ 0x2 = Disable
+ 0x6 = Enable */
+// ----------------
+void HidOutputReport(u16 _channelID, wm_report* sr) {
+ INFO_LOG(WII_IPC_WIIMOTE, "===========================================================");
+ INFO_LOG(WII_IPC_WIIMOTE, "HidOutputReport (0x%02x)", sr->channel);
+ std::string Temp;
+
+ switch(sr->channel)
+ {
+ case WM_RUMBLE:
+ // TODO: Implement rumble for real wiimotes
+ break;
+ case WM_LEDS: // 0x11
+ WmLeds(_channelID, (wm_leds*)sr->data);
+ break;
+ case WM_DATA_REPORTING: // 0x12
+ WmDataReporting(_channelID, (wm_data_reporting*)sr->data);
+ break;
+ case WM_REQUEST_STATUS: // 0x15
+ if (!g_Config.bUseRealWiimote || !g_RealWiiMotePresent) WmRequestStatus(_channelID, (wm_request_status*)sr->data);
+ //Temp = ArrayToString(sr->data, sizeof(wm_request_status), 0);
+ //INFO_LOG(CONSOLE, "\n%s: InterruptChannel: %s\n", Tm().c_str(), Temp.c_str());
+ break;
+ case WM_READ_DATA: // 0x17
+ if (!g_Config.bUseRealWiimote || !g_RealWiiMotePresent) WmReadData(_channelID, (wm_read_data*)sr->data);
+ break;
+
+ /* This enables or disables the IR lights, we update the global variable g_IR
+ so that WmRequestStatus() knows about it */
+ case WM_IR_PIXEL_CLOCK: // 0x13
+ case WM_IR_LOGIC: // 0x1a
+ WARN_LOG(WII_IPC_WIIMOTE, " IR Enable 0x%02x: 0x%02x", sr->channel, sr->data[0]);
+ INFO_LOG(CONSOLE, "IR Enable/Disable 0x%02x: 0x%02x\n", sr->channel, sr->data[0]);
+ if(sr->data[0] == 0x02) g_IR = 0;
+ else if(sr->data[0] == 0x06) g_IR = 1;
+ break;
+
+ case WM_WRITE_DATA: // 0x16
+ WmWriteData(_channelID, (wm_write_data*)sr->data);
+ break;
+
+ case WM_SPEAKER_ENABLE: // 0x14
+ INFO_LOG(WII_IPC_WIIMOTE, " WM Speaker Enable 0x%02x: 0x%02x", sr->channel, sr->data[0]);
+ //INFO_LOG(CONSOLE, "Speaker Enable/Disable 0x%02x: 0x%02x\n", sr->channel, sr->data[0]);
+ if(sr->data[0] == 0x02) g_Speaker = 0;
+ else if(sr->data[0] == 0x06) g_Speaker = 1;
+ break;
+ case WM_SPEAKER_MUTE: // 0x19
+ INFO_LOG(WII_IPC_WIIMOTE, " WM Mute Enable 0x%02x: 0x%02x", sr->channel, sr->data[0]);
+ //INFO_LOG(CONSOLE, "Speaker Mute/Unmute 0x%02x: 0x%02x\n", sr->channel, sr->data[0]);
+ if(sr->data[0] == 0x02) g_SpeakerVoice = 0; // g_SpeakerVoice
+ else if(sr->data[0] == 0x06) g_SpeakerVoice = 1;
+ break;
+ case WM_WRITE_SPEAKER_DATA: // 0x18
+ break;
+
+ default:
+ ERROR_LOG(WII_IPC_WIIMOTE, "HidOutputReport: Unknown channel 0x%02x", sr->channel);
+ PanicAlert("HidOutputReport: Unknown channel 0x%02x", sr->channel);
+ return;
+ }
+ INFO_LOG(WII_IPC_WIIMOTE, "===========================================================");
+}
+
+
+// ===================================================
+/* Generate the right header for wm reports. The returned values is the length of the header before
+ the data begins. It's always two for all reports 0x20 - 0x22, 0x30 - 0x37 */
+// ----------------
+int WriteWmReport(u8* dst, u8 channel)
+{
+ // Update the first byte to 0xa1
+ u32 Offset = 0;
+ hid_packet* pHidHeader = (hid_packet*)(dst + Offset);
+ Offset += sizeof(hid_packet);
+ pHidHeader->type = HID_TYPE_DATA;
+ pHidHeader->param = HID_PARAM_INPUT;
+
+ // Update the second byte to the current report type 0x20 - 0x22, 0x30 - 0x37
+ wm_report* pReport = (wm_report*)(dst + Offset);
+ Offset += sizeof(wm_report);
+ pReport->channel = channel;
+ return Offset;
+}
+
+
+// ===================================================
+/* LED (blue lights) report. */
+// ----------------
+void WmLeds(u16 _channelID, wm_leds* leds) {
+ INFO_LOG(WII_IPC_WIIMOTE, "===========================================================");
+ INFO_LOG(WII_IPC_WIIMOTE, " Set LEDs");
+ INFO_LOG(WII_IPC_WIIMOTE, " Leds: %x", leds->leds);
+ INFO_LOG(WII_IPC_WIIMOTE, " Rumble: %x", leds->rumble);
+
+ g_Leds = leds->leds;
+
+ INFO_LOG(WII_IPC_WIIMOTE, "===========================================================");
+}
+
+
+// ===================================================
+/* This will generate the 0x22 acknowledgment after all Input reports. It will
+ have the form a1 22 00 00 _reportID 00. The first two bytes are the core buttons data,
+ they are 00 00 when nothing is pressed. The last byte is the success code 00. */
+// ----------------
+void WmSendAck(u16 _channelID, u8 _reportID, u32 address)
+{
+ u8 DataFrame[1024];
+ u32 Offset = 0;
+
+ // Header
+ hid_packet* pHidHeader = (hid_packet*)(DataFrame + Offset);
+ pHidHeader->type = HID_TYPE_DATA;
+ pHidHeader->param = HID_PARAM_INPUT;
+ Offset += sizeof(hid_packet);
+
+ wm_acknowledge* pData = (wm_acknowledge*)(DataFrame + Offset);
+ pData->Channel = WM_WRITE_DATA_REPLY;
+ pData->unk0 = 0;
+ pData->unk1 = 0;
+ pData->reportID = _reportID;
+ pData->errorID = 0;
+ Offset += sizeof(wm_acknowledge);
+
+ INFO_LOG(WII_IPC_WIIMOTE, " WMSendAck()");
+ INFO_LOG(WII_IPC_WIIMOTE, " Report ID: %02x", _reportID);
+ //std::string Temp = ArrayToString(DataFrame, Offset, 0);
+ //LOGV(WII_IPC_WIIMOTE, 2, " Data: %s", Temp.c_str());
+ //INFO_LOG(CONSOLE, "%s: WMSendAck: %s\n", Tm(true).c_str(), Temp.c_str());
+
+ /* Debug. Write the report for extension registry writes.
+ if((_reportID == 0x16 || _reportID == 0x17) && ((address >> 16) & 0xfe) == 0xa4)
+ {
+ INFO_LOG(CONSOLE, "\nWMSendAck Report ID: %02x Encryption: %02x\n", _reportID, g_RegExt[0xf0]);
+ INFO_LOG(CONSOLE, "Data: %s\n", Temp.c_str());
+ }*/
+
+ g_WiimoteInitialize.pWiimoteInput(_channelID, DataFrame, Offset);
+
+ // Debugging
+ ReadDebugging(true, DataFrame, Offset);
+}
+
+
+// ===================================================
+/* Read data from Wiimote and Extensions registers. */
+// ----------------
+void WmReadData(u16 _channelID, wm_read_data* rd)
+{
+ INFO_LOG(WII_IPC_WIIMOTE, "===========================================================");
+ u32 address = convert24bit(rd->address);
+ u16 size = convert16bit(rd->size);
+ std::string Temp;
+ INFO_LOG(WII_IPC_WIIMOTE, "Read data");
+ INFO_LOG(WII_IPC_WIIMOTE, " Address space: %x", rd->space);
+ INFO_LOG(WII_IPC_WIIMOTE, " Address: 0x%06x", address);
+ INFO_LOG(WII_IPC_WIIMOTE, " Size: 0x%04x", size);
+ INFO_LOG(WII_IPC_WIIMOTE, " Rumble: %x", rd->rumble);
+
+ //u32 _address = address;
+ std::string Tmp; // Debugging
+
+ /* Now we determine what address space we are reading from. Space 0 is Eeprom and
+ space 1 and 2 is the registers. */
+ if(rd->space == WM_SPACE_EEPROM)
+ {
+ if (address + size > WIIMOTE_EEPROM_SIZE)
+ {
+ PanicAlert("WmReadData: address + size out of bounds");
+ return;
+ }
+ SendReadDataReply(_channelID, g_Eeprom + address, address, (u8)size);
+ /*INFO_LOG(CONSOLE, "Read RegEeprom: Size: %i, Address: %08x, Offset: %08x\n",
+ size, address, (address & 0xffff));*/
+ }
+ else if(rd->space == WM_SPACE_REGS1 || rd->space == WM_SPACE_REGS2)
+ {
+ u8* block;
+ u32 blockSize;
+ switch((address >> 16) & 0xFE)
+ {
+ case 0xA2:
+ block = g_RegSpeaker;
+ blockSize = WIIMOTE_REG_SPEAKER_SIZE;
+ INFO_LOG(WII_IPC_WIIMOTE, " Case 0xa2: g_RegSpeaker");
+ /*Tmp = ArrayToString(g_RegSpeaker, size, (address & 0xffff));
+ //LOGV(WII_IPC_WIIMOTE, 0, " Data: %s", Temp.c_str());
+ INFO_LOG(CONSOLE, "Read RegSpkr: Size %i Address %08x Offset %08x\nData %s\n",
+ size, address, (address & 0xffff), Tmp.c_str());*/
+ break;
+ case 0xA4:
+ block = g_RegExt;
+ blockSize = WIIMOTE_REG_EXT_SIZE;
+ INFO_LOG(WII_IPC_WIIMOTE, " Case 0xa4: Read ExtReg");
+ /*Tmp = ArrayToString(g_RegExt, size, (address & 0xffff), 40);
+ //LOGV(WII_IPC_WIIMOTE, 0, " Data: %s", Temp.c_str());
+ INFO_LOG(CONSOLE, "Read RegExt: Size %i Address %08x Offset %08x\nData %s\n",
+ size, address, (address & 0xffff), Tmp.c_str());*/
+ break;
+ case 0xB0:
+ block = g_RegIr;
+ blockSize = WIIMOTE_REG_IR_SIZE;
+ INFO_LOG(WII_IPC_WIIMOTE, " Case: 0xb0 g_RegIr");
+ /*Tmp = ArrayToString(g_RegIr, size, (address & 0xffff));
+ //LOGV(WII_IPC_WIIMOTE, 0, " Data: %s", Temp.c_str());
+ INFO_LOG(CONSOLE, "Read RegIR: Size %i Address %08x Offset %08x\nData %s\n",
+ size, address, (address & 0xffff), Tmp.c_str());*/
+ break;
+ default:
+ ERROR_LOG(WII_IPC_WIIMOTE, "WmWriteData: bad register block!");
+ PanicAlert("WmWriteData: bad register block!");
+ return;
+ }
+
+
+ // -----------------------------------------
+ // Encrypt data that is read from the Wiimote Extension Register
+ // -------------
+ if(((address >> 16) & 0xfe) == 0xa4)
+ {
+ /* Debugging
+ INFO_LOG(CONSOLE, "\n\nWmReadData Address: %08x Offset: %08x Size: %i byte\n",
+ address, address & 0xffff, (u8)size);
+ // Debugging
+ u32 offset = address & 0xffff;
+ std::string Temp = ArrayToString(g_RegExt, size, offset);
+ INFO_LOG(CONSOLE, "Unencrypted data:\n%s\n", Temp.c_str());*/
+
+ // Check if encrypted reads is on
+ if(g_RegExt[0xf0] == 0xaa)
+ {
+ /* Copy the registry to a temporary space. We don't want to change the unencrypted
+ data in the registry */
+ memcpy(g_RegExtTmp, g_RegExt, sizeof(g_RegExt));
+
+ // Encrypt g_RegExtTmp at that location
+ wiimote_encrypt(&g_ExtKey, &g_RegExtTmp[address & 0xffff], (address & 0xffff), (u8)size);
+
+ // Update the block that SendReadDataReply will eventually send to the Wii
+ block = g_RegExtTmp;
+
+ /* Debugging: Show the encrypted data
+ std::string Temp = ArrayToString(g_RegExtTmp, size, offset);
+ INFO_LOG(CONSOLE, "Encrypted data:\n%s\n", Temp.c_str());*/
+ }
+ }
+ //-------------
+
+ address &= 0xFFFF;
+ if(address + size > blockSize) {
+ PanicAlert("WmReadData: address + size out of bounds!");
+ return;
+ }
+
+ // Let this function process the message and send it to the Wii
+ SendReadDataReply(_channelID, block + address, address, (u8)size);
+ }
+ else
+ {
+ PanicAlert("WmReadData: unimplemented parameters (size: %i, addr: 0x%x!", size, rd->space);
+ }
+
+ INFO_LOG(WII_IPC_WIIMOTE, "===========================================================");
+}
+// ===================================================
+/* Here we produce the actual 0x21 Input report that we send to the Wii. The message
+ is divided into 16 bytes pieces and sent piece by piece. There will be five formatting
+ bytes at the begging of all reports. A common format is 00 00 f0 00 20, the 00 00
+ means that no buttons are pressed, the f means 16 bytes in the message, the 0
+ means no error, the 00 20 means that the message is at the 00 20 offest in the
+ registry that was read.
+
+ _Base: The data beginning at _Base[0]
+ _Address: The starting address inside the registry, this is used to check for out of bounds reading
+ _Size: The total size to send
+ */
+// ----------------
+void SendReadDataReply(u16 _channelID, void* _Base, u16 _Address, u8 _Size)
+{
+ INFO_LOG(WII_IPC_WIIMOTE, "=========================================");
+ int dataOffset = 0;
+ const u8* data = (const u8*)_Base;
+
+ while (_Size > 0)
+ {
+ u8 DataFrame[1024];
+ // Write the first two bytes to DataFrame
+ u32 Offset = WriteWmReport(DataFrame, WM_READ_DATA_REPLY);
+
+ // Limit the size to 16 bytes
+ int copySize = _Size;
+ if (copySize > 16) copySize = 16;
+
+ // Connect pReply->data to the almost empty DataFrame
+ wm_read_data_reply* pReply = (wm_read_data_reply*)(DataFrame + Offset);
+ // Now we increase Offset to the final size of the report
+ Offset += sizeof(wm_read_data_reply);
+ // Add header values
+ pReply->buttons = 0;
+ pReply->error = 0;
+ // 0x1 means two bytes, 0xf means 16 bytes
+ pReply->size = (copySize - 1) & 0xf;
+ pReply->address = Common::swap16(_Address + dataOffset);
+
+ // Write a pice of _Base to DataFrame
+ memcpy(pReply->data, data + dataOffset, copySize);
+
+ // Check if we have less than 16 bytes left to send
+ if(copySize < 16) memset(pReply->data + copySize, 0, 16 - copySize);
+
+ // Update DataOffset for the next loop
+ dataOffset += copySize;
+
+ /* Out of bounds. The real Wiimote generate an error for the first request to 0x1770
+ if we dont't replicate that the game will never read the capibration data at the
+ beginning of Eeprom. I think this error is supposed to occur when we try to read above
+ the freely usable space that ends at 0x16ff. */
+ if (Common::swap16(pReply->address + pReply->size) > WIIMOTE_EEPROM_FREE_SIZE)
+ {
+ pReply->size = 0x0f;
+ pReply->error = 0x08;
+ }
+
+ // Logging
+ INFO_LOG(WII_IPC_WIIMOTE, " SendReadDataReply()");
+ DEBUG_LOG(WII_IPC_WIIMOTE, " Buttons: 0x%04x", pReply->buttons);
+ DEBUG_LOG(WII_IPC_WIIMOTE, " Error: 0x%x", pReply->error);
+ DEBUG_LOG(WII_IPC_WIIMOTE, " Size: 0x%x", pReply->size);
+ DEBUG_LOG(WII_IPC_WIIMOTE, " Address: 0x%04x", pReply->address);
+ /*INFO_LOG(CONSOLE, " SendReadDataReply()\n");
+ INFO_LOG(CONSOLE, " Offset: 0x%x\n", Offset);
+ INFO_LOG(CONSOLE, " dataOffset: 0x%x\n", dataOffset);
+ INFO_LOG(CONSOLE, " copySize: 0x%x\n", copySize);
+ INFO_LOG(CONSOLE, " Size: 0x%x\n", pReply->size);
+ INFO_LOG(CONSOLE, " Address: 0x%04x\n", Common::swap16(pReply->address));*/
+ //std::string Temp = ArrayToString(data, 0x40);
+ //INFO_LOG(CONSOLE, "Data:\n%s\n", Temp.c_str());
+
+ // Send a piece
+ g_WiimoteInitialize.pWiimoteInput(_channelID, DataFrame, Offset);
+ // Update the size that is left
+ _Size -= copySize;
+
+ // Debugging
+ ReadDebugging(true, DataFrame, Offset);
+ }
+
+ if (_Size != 0) {
+ ERROR_LOG(WII_IPC_WIIMOTE, "WiiMote-Plugin: SendReadDataReply() failed");
+ PanicAlert("WiiMote-Plugin: SendReadDataReply() failed");
+ }
+ INFO_LOG(WII_IPC_WIIMOTE, "==========================================");
+}
+// ================
+
+
+// ===================================================
+/* Write data to Wiimote and Extensions registers. */
+// ----------------
+void WmWriteData(u16 _channelID, wm_write_data* wd)
+{
+ INFO_LOG(WII_IPC_WIIMOTE, "========================================================");
+ u32 address = convert24bit(wd->address);
+ INFO_LOG(WII_IPC_WIIMOTE, "Write data");
+ DEBUG_LOG(WII_IPC_WIIMOTE, " Address space: %x", wd->space);
+ DEBUG_LOG(WII_IPC_WIIMOTE, " Address: 0x%06x", address);
+ DEBUG_LOG(WII_IPC_WIIMOTE, " Size: 0x%02x", wd->size);
+ DEBUG_LOG(WII_IPC_WIIMOTE, " Rumble: %x", wd->rumble);
+ //std::string Temp = ArrayToString(wd->data, wd->size);
+ //LOGV(WII_IPC_WIIMOTE, 0, " Data: %s", Temp.c_str());
+
+ // Write to EEPROM
+ if(wd->size <= 16 && wd->space == WM_SPACE_EEPROM)
+ {
+ if(address + wd->size > WIIMOTE_EEPROM_SIZE) {
+ ERROR_LOG(WII_IPC_WIIMOTE, "WmWriteData: address + size out of bounds!");
+ PanicAlert("WmWriteData: address + size out of bounds!");
+ return;
+ }
+ memcpy(g_Eeprom + address, wd->data, wd->size);
+ /*INFO_LOG(CONSOLE, "Write RegEeprom: Size: %i, Address: %08x, Offset: %08x\n",
+ wd->size, address, (address & 0xffff));*/
+ }
+ // Write to registers
+ else if(wd->size <= 16 && (wd->space == WM_SPACE_REGS1 || wd->space == WM_SPACE_REGS2))
+ {
+ u8* block;
+ u32 blockSize;
+ switch((address >> 16) & 0xFE)
+ {
+ case 0xA2:
+ block = g_RegSpeaker;
+ blockSize = WIIMOTE_REG_SPEAKER_SIZE;
+ INFO_LOG(WII_IPC_WIIMOTE, " Case 0xa2: RegSpeaker");
+ /*INFO_LOG(CONSOLE, "Write RegSpeaker: Size: %i, Address: %08x, Offset: %08x\n",
+ wd->size, address, (address & 0xffff));
+ INFO_LOG(CONSOLE, "Data: %s\n", Temp.c_str());*/
+ break;
+ case 0xA4:
+ block = g_RegExt; // Extension Controller register
+ blockSize = WIIMOTE_REG_EXT_SIZE;
+ //LOGV(WII_IPC_WIIMOTE, 0, " *******************************************************");
+ INFO_LOG(WII_IPC_WIIMOTE, " Case 0xa4: ExtReg");
+ //LOGV(WII_IPC_WIIMOTE, 0, " *******************************************************");
+ /*INFO_LOG(CONSOLE, "Write RegExt Size: %i Address: %08x Offset: %08x \n",
+ wd->size, address, (address & 0xffff));
+ INFO_LOG(CONSOLE, "Data: %s\n", Temp.c_str());*/
+ break;
+ case 0xB0:
+ block = g_RegIr;
+ blockSize = WIIMOTE_REG_IR_SIZE;
+ INFO_LOG(WII_IPC_WIIMOTE, " Case 0xb0: RegIr");
+ /*INFO_LOG(CONSOLE, "Write RegIR Size: %i Address: %08x Offset: %08x \n",
+ wd->size, address, (address & 0xffff));
+ INFO_LOG(CONSOLE, "Data: %s\n", Temp.c_str());*/
+ break;
+ default:
+ ERROR_LOG(WII_IPC_WIIMOTE, "WmWriteData: bad register block!");
+ PanicAlert("WmWriteData: bad register block!");
+ return;
+ }
+
+ // Remove for example 0xa40000 from the address
+ address &= 0xFFFF;
+
+ // Check if the address is within bounds
+ if(address + wd->size > blockSize) {
+ ERROR_LOG(WII_IPC_WIIMOTE, "WmWriteData: address + size out of bounds!");
+ PanicAlert("WmWriteData: address + size out of bounds!");
+ return;
+ }
+
+ // Finally write the registers to the right structure
+ memcpy(block + address, wd->data, wd->size);
+
+
+ // -----------------------------------------
+ // Generate key for the Wiimote Extension
+ // -------------
+ if(blockSize == WIIMOTE_REG_EXT_SIZE)
+ {
+ /* Debugging. Write the data.
+ INFO_LOG(CONSOLE, "Data: %s\n", Temp.c_str());
+ INFO_LOG(CONSOLE, "Current address: %08x\n", address); */
+
+ /* Run the key generation on all writes in the key area, it doesn't matter
+ that we send it parts of a key, only the last full key will have an
+ effect */
+ if(address >= 0x40 && address <= 0x4c)
+ wiimote_gen_key(&g_ExtKey, &g_RegExt[0x40]);
+ }
+ // -------------
+
+
+ } else {
+ ERROR_LOG(WII_IPC_WIIMOTE, "WmWriteData: unimplemented parameters!");
+ PanicAlert("WmWriteData: unimplemented parameters!");
+ }
+
+ /* Just added for home brew... Isn't it enough that we call this from
+ InterruptChannel()? Or is there a separate route here that don't pass though
+ InterruptChannel()? */
+ //WmSendAck(_channelID, WM_WRITE_DATA, _address);
+ INFO_LOG(WII_IPC_WIIMOTE, "==========================================================");
+}
+
+// ===================================================
+/* Here we produce a 0x20 status report to send to the Wii. We currently ignore the status
+ request rs and all its eventual instructions it may include (for example turn off
+ rumble or something else) and just send the status report. */
+// ----------------
+void WmRequestStatus(u16 _channelID, wm_request_status* rs, int Extension)
+{
+ //PanicAlert("WmRequestStatus");
+ INFO_LOG(WII_IPC_WIIMOTE, "================================================");
+ INFO_LOG(WII_IPC_WIIMOTE, " Request Status");
+ INFO_LOG(WII_IPC_WIIMOTE, " Rumble: %x", rs->rumble);
+ INFO_LOG(WII_IPC_WIIMOTE, " Channel: %04x", _channelID);
+
+ //SendStatusReport();
+ u8 DataFrame[1024];
+ u32 Offset = WriteWmReport(DataFrame, WM_STATUS_REPORT);
+
+ wm_status_report* pStatus = (wm_status_report*)(DataFrame + Offset);
+ Offset += sizeof(wm_status_report);
+ memset(pStatus, 0, sizeof(wm_status_report)); // fill the status report with zeroes
+
+ // Status values
+ pStatus->battery_low = 0; // battery is okay
+ pStatus->leds = g_Leds; // leds are 4 bit
+ pStatus->ir = g_IR; // 1 bit
+ pStatus->speaker = g_Speaker; // 1 bit
+ /* Battery levels in voltage
+ 0x00 - 0x32: level 1
+ 0x33 - 0x43: level 2
+ 0x33 - 0x54: level 3
+ 0x55 - 0xff: level 4 */
+ pStatus->battery = 0x5f; // fully charged
+
+ // Check if we have a specific order about the extension status
+ if (Extension == -1)
+ {
+ // Read config value for this one
+ if(g_Config.bNunchuckConnected || g_Config.bClassicControllerConnected)
+ pStatus->extension = 1;
+ else
+ pStatus->extension = 0;
+ }
+ else
+ {
+ if(Extension)
+ pStatus->extension = 1;
+ else
+ pStatus->extension = 0;
+ }
+
+ INFO_LOG(WII_IPC_WIIMOTE, " Extension: %x", pStatus->extension);
+ INFO_LOG(WII_IPC_WIIMOTE, " SendStatusReport()");
+ DEBUG_LOG(WII_IPC_WIIMOTE, " Flags: 0x%02x", pStatus->padding1[2]);
+ DEBUG_LOG(WII_IPC_WIIMOTE, " Battery: %d", pStatus->battery);
+
+ g_WiimoteInitialize.pWiimoteInput(_channelID, DataFrame, Offset);
+ INFO_LOG(WII_IPC_WIIMOTE, "=================================================");
+
+ // Debugging
+ ReadDebugging(true, DataFrame, Offset);
+}
+
+} // WiiMoteEmu
diff --git a/Source/Plugins/Plugin_Wiimote-testing/Src/EmuSubroutines.h b/Source/Plugins/Plugin_Wiimote-testing/Src/EmuSubroutines.h
new file mode 100644
index 0000000000..fc583fd165
--- /dev/null
+++ b/Source/Plugins/Plugin_Wiimote-testing/Src/EmuSubroutines.h
@@ -0,0 +1,76 @@
+// Copyright (C) 2003-2008 Dolphin Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official SVN repository and contact information can be found at
+// http://code.google.com/p/dolphin-emu/
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Include
+// ŻŻŻŻŻŻŻŻŻ
+#ifndef _EMU_SUBFUNCTIONS_
+#define _EMU_SUBFUNCTIONS_
+
+#include "pluginspecs_wiimote.h"
+
+#include
+#include
+
+#include "Common.h" // Common
+#include "main.h"
+#include "wiimote_hid.h" // Local
+#include "EmuDefinitions.h"
+#include "Encryption.h"
+#include "Logging.h" // for startConsoleWin, Console::Print, GetConsoleHwnd
+////////////////////////////
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Declarations and definitions
+// ŻŻŻŻŻŻŻŻŻ
+extern SWiimoteInitialize g_WiimoteInitialize;
+
+
+namespace WiiMoteEmu
+{
+
+void HidOutputReport(u16 _channelID, wm_report* sr);
+
+void WmLeds(u16 _channelID, wm_leds* leds);
+void WmReadData(u16 _channelID, wm_read_data* rd);
+void WmWriteData(u16 _channelID, wm_write_data* wd);
+void WmRequestStatus(u16 _channelID, wm_request_status* rs, int Extension = -1);
+void WmRequestStatus_(u16 _channelID, int a);
+void WmDataReporting(u16 _channelID, wm_data_reporting* dr);
+
+void SendReadDataReply(u16 _channelID, void* _Base, u16 _Address, u8 _Size);
+void SendReportCoreAccel(u16 _channelID);
+void SendReportCoreAccelIr12(u16 _channelID);
+void SendReportCore(u16 _channelID);
+void SendReportCoreAccelExt16(u16 _channelID);
+void SendReportCoreAccelIr10Ext(u16 _channelID);
+
+int WriteWmReport(u8* dst, u8 channel);
+void WmSendAck(u16 _channelID, u8 _reportID, u32 address);
+
+void FillReportAcc(wm_accel& _acc);
+void FillReportInfo(wm_core& _core);
+void FillReportIR(wm_ir_extended& _ir0, wm_ir_extended& _ir1);
+void FillReportIRBasic(wm_ir_basic& _ir0, wm_ir_basic& _ir1);
+void FillReportExtension(wm_extension& _ext);
+void FillReportClassicExtension(wm_classic_extension& _ext);
+
+} // namespace
+
+#endif //_EMU_DECLARATIONS_
diff --git a/Source/Plugins/Plugin_Wiimote-testing/Src/Encryption.cpp b/Source/Plugins/Plugin_Wiimote-testing/Src/Encryption.cpp
new file mode 100644
index 0000000000..b3475406a9
--- /dev/null
+++ b/Source/Plugins/Plugin_Wiimote-testing/Src/Encryption.cpp
@@ -0,0 +1,303 @@
+// Copyright (C) 2003-2008 Dolphin Project.
+// Copyright (C) Hector Martin "marcan" (hector@marcansoft.com)
+
+// 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 "pluginspecs_wiimote.h"
+#include "Common.h"
+#include "Logging.h" // for startConsoleWin, Console::Print, GetConsoleHwnd
+#include "Encryption.h"
+
+
+u8 ans_tbl[7][6] = {
+ {0xA8,0x77,0xA6,0xE0,0xF7,0x43},
+ {0x5A,0x35,0x85,0xE2,0x72,0x97},
+ {0x8F,0xB7,0x1A,0x62,0x87,0x38},
+ { 0xD,0x67,0xC7,0xBE,0x4F,0x3E},
+ {0x20,0x76,0x37,0x8F,0x68,0xB7},
+ {0xA9,0x26,0x3F,0x2B,0x10,0xE3},
+ {0x30,0x7E,0x90, 0xE,0x85, 0xA},
+};
+
+u8 tsbox[256] = {
+ 0x70,0x51, 3,0x86,0x40, 0xD,0x4F,0xEB,0x3E,0xCC,0xD1,0x87,0x35,0xBD,0xF5, 0xB,
+ 0x5E,0xD0,0xF8,0xF2,0xD5,0xE2,0x6C,0x31, 0xC,0xAD,0xFC,0x21,0xC3,0x78,0xC1, 6,
+ 0xC2,0x4C,0x55,0xE6,0x4A,0x34,0x48,0x11,0x1E,0xDA,0xE7,0x1A,0x84,0xA0,0x96,0xA7,
+ 0xE3,0x7F,0xAF,0x63,0x9C,0xFA,0x23,0x5B,0x79,0xC8,0x9E,0xBA,0xB2,0xC9,0x22,0x12,
+ 0x4B,0xB3,0xA1,0xB6,0x32,0x49,0xA2,0xE1,0x89,0x39,0x10,0x66,0xC5, 7,0x8F,0x54,
+ 0xEA,0x91,0xCA,0x3F,0xF9,0x19,0xF0,0xD7,0x46,0xBC,0x28,0x1B,0x61,0xE8,0x2F,0x6A,
+ 0xAE,0x9D,0xF6,0x4E, 9,0x14,0x77,0x4D,0xDB,0x1F,0x2E,0x7B,0x7C,0xF1,0x43,0xA3,
+ 0,0xB8,0x13,0x8C,0x85,0xB9,0x29,0x75,0x88,0xFD,0xD2,0x56,0x1C,0x50,0x97,0x41,
+ 0xE5,0x3B,0x60,0xB5,0xC0,0x64,0xEE,0x98,0xD6,0x2D,0x25,0xA4,0xAA,0xCD,0x7D,0xA8,
+ 0x83,0xC6,0xAB,0xBE,0x44,0x99,0x26,0x3C,0xCE,0x9F,0xBF,0xD3,0xCB,0x76,0x7A,0x7E,
+ 0x82, 1,0x8A,0x9A,0x80,0x1D, 0xE,0xB0,0x5C,0xD4,0x38,0x62,0xF4,0x30,0xE0,0x8E,
+ 0x53,0xB7, 2,0x57,0xAC,0xA6,0x52, 0xA,0x6D,0x92,0x65,0x17,0x24,0x33,0x45,0x72,
+ 0x74,0xB1,0xB4,0xF7,0x5D,0xED,0x2C,0xFF,0x47,0x37,0x5A,0x90,0xBB,0xDF,0x2A,0x16,
+ 0x59,0x95,0xD9,0xC4,0x27,0x67,0x73,0xC7,0x68,0xFE,0xA5,0xDD,0x6B,0x5F,0x93,0xD8,
+ 0xEC, 5,0x3A,0x8D,0x6E,0xFB,0x3D,0xA9,0x69,0x36,0xF3,0x94,0xDE,0xEF,0x15,0x6F,
+ 0x8B,0x9B, 8, 0xF,0xDC,0x81,0x18,0x20, 4,0xE4,0x71,0xCF,0xE9,0x2B,0x42,0x58,
+};
+
+u8 sboxes[8][256] = {
+ {
+ 1,0xA0,0xA9,0x62,0xD6,0x3F,0x85,0xA7,0xB6,0xD4,0xFA,0x15,0x66,0x17, 9,0xBD,
+ 0x5D,0x14,0x34,0x26,0x59,0x72,0x91,0x54, 6,0x4F,0xF8,0xB0,0x5B,0x74,0x93,0x99,
+ 0x8C,0xF2,0x45,0xCD,0xEA,0x4E,0xAD,0x10,0x4A,0xE5,0xCA,0xEE,0xDF,0xC6,0x6F,0x9F,
+ 0x88,0x8E, 2,0xCC, 8,0xA8,0x77,0x94,0x6D,0x21,0xB1,0x28,0xE4,0x39,0x79,0x96,
+ 0x60,0x71,0x81,0x16,0x2E,0xE6,0x78,0xB9,0xC4,0x46,0x9A,0x42,0xAE,0xB7,0x7C,0x43,
+ 0xB3,0x22,0x1A,0x86,0xC2,0x32,0x3D,0x2D,0x9C,0xD2,0x29,0xE9,0x63,0x9B,0xD1,0x31,
+ 0x38,0x5E,0x1E,0x36,0x41,0xBB, 3,0x18,0x2B,0x3E,0xBF,0x68,0x61,0xFC,0x52,0xC0,
+ 0xDE,0xE0, 0xA,0x58,0x13,0x5A, 0,0xBE,0x1C,0x90, 0xE,0x53,0x12,0xFD,0xE2,0x6E,
+ 0xBA,0xCE,0x24,0x27,0x44,0x7F,0x87,0xA3,0xA1,0xD5,0x50,0x40,0xE3,0xF9,0x83,0xF7,
+ 0xC7,0xA2,0x35,0xC8,0xDB,0x19,0xAB,0x2F,0x11,0x25,0xED,0x33,0x9E,0x55,0xE1,0x48,
+ 0xAF,0x73,0x84,0xDA,0x2A,0xAA,0x51,0xEB,0x9D,0x95,0xB2,0xCB,0xE7,0x70,0x80,0xFE,
+ 0x4C,0x65, 4,0xEF,0xC5,0xF1,0xC3,0x3A,0xB4,0xF5,0x5F,0x23,0x89,0xDD,0x30,0xA5,
+ 0x8B,0xD3,0xF6,0xDC,0x4D,0x64,0xD7,0xF0,0x8F,0xEC,0x56,0x37,0x5C,0xA4, 0xD, 7,
+ 0x76,0x8A,0x2C, 0xB,0xB5,0xD8,0xC1,0x1F,0xE8,0x3B,0xF4,0x4B,0x1B,0x47,0x6C,0x49,
+ 0x67,0x7B,0x92,0xCF,0x75,0x7E,0x20,0xD9,0x7D,0x3C,0x97,0x7A,0xD0, 5,0x6B, 0xF,
+ 0x1D,0xFB,0x82,0x98,0x57,0x8D,0xF3,0x6A,0xBC,0xAC,0xC9,0xA6,0xFF,0xB8,0x69, 0xC,
+ },
+ {
+ 0x4C,0x4D,0x72, 7,0x5A,0x49,0x33,0x8D,0xA2,0xAB,0x46,0x3D,0x63, 0xD,0xA0,0x97,
+ 0xFF,0xF0,0xF5,0xFA,0xC0,0xE9,0xDB,0x62,0xE4,0xE1,0x74,0x43,0xDC,0x86,0x18,0x29,
+ 0x37,0xF4, 6,0xE2,0xED,0x6F,0x90,0x48,0x1E,0x2D,0x1D,0xEA,0x73,0x94,0x54,0xDF,
+ 0x25,0xF6,0x47,0x27,0xD9,0x11,0x77,0xC9,0x84,0x1C,0x5B,0x5C,0x51,0x81,0xA6,0x22,
+ 0x3E,0x24,0x96,0xC8,0x8A,0xEC,0x82,0x7C, 9,0xB8,0x45,0x4A,0x57,0xBB,0x2F,0x50,
+ 0x75,0x8E,0x61,0x70,0x8C,0x6C,0xAF,0xD0,0xFD,0xB4,0x1B,0xAE,0xDE,0xFE,0x3B,0xB5,
+ 0x36,0xBD,0x55, 1, 0xE,0x9C,0x41,0x56,0x5F,0xB3,0x26, 3,0x83,0xBA,0x13,0x4B,
+ 0xCA,0xC5, 0xA,0xF8,0x60,0xA5,0xB9,0xC7,0xC3,0x98,0x32,0xFB,0x12,0xF9,0xA7,0x92,
+ 0xAA,0x68,0xF3,0x78,0x7E, 5,0x20,0x21, 2,0xE8,0xBF,0xF2,0xB0,0x59,0x8F,0xD2,
+ 0xCB,0x87,0x65,0x15,0xF1,0x1A,0xB2,0x30,0xAD,0xEE,0x58,0xA3,0x8B,0x66,0x1F,0x2C,
+ 0xD7,0x5D,0x19,0x85,0xA8,0xE6,0xD3,0x6B,0xA1, 0xC,0x91,0x93,0x6A,0x5E, 0xB,0x79,
+ 0xE3,0xDD, 0,0x4F,0x3C,0x89,0x6E,0x71,0x69,0xA9,0xAC,0x40,0xE5,0x99,0x28,0xC6,
+ 0x31,0x4E,0x7A,0xCD, 8,0x9E,0x7D,0xEF,0x17,0xFC,0x88,0xD8,0xA4,0x6D,0x44,0x95,
+ 0xD1,0xB7,0xD4,0x9B,0xBE,0x2A,0x34,0x64,0x2B,0xCF,0x2E,0xEB,0x38,0xCE,0x23,0xE0,
+ 0x3A,0x3F,0xF7,0x7B,0x9F,0x10,0x53,0xBC,0x52,0x67,0x16,0xE7,0x80,0x76, 4,0xC4,
+ 0xB6,0xC1,0xC2,0x7F,0x9A,0xDA,0xD5,0x39,0x42,0x14,0x9D,0xB1, 0xF,0x35,0xD6,0xCC,
+ },
+ {
+ 0xB9,0xDA,0x38, 0xC,0xA2,0x9C, 9,0x1F, 6,0xB1,0xB6,0xFD,0x1A,0x69,0x23,0x30,
+ 0xC4,0xDE, 1,0xD1,0xF4,0x58,0x29,0x37,0x1C,0x7D,0xD5,0xBF,0xFF,0xBD,0xC8,0xC9,
+ 0xCF,0x65,0xBE,0x7B,0x78,0x97,0x98,0x67, 8,0xB3,0x26,0x57,0xF7,0xFA,0x40,0xAD,
+ 0x8E,0x75,0xA6,0x7C,0xDB,0x91,0x8B,0x51,0x99,0xD4,0x17,0x7A,0x90,0x8D,0xCE,0x63,
+ 0xCB,0x4E,0xA0,0xAB,0x18,0x3A,0x5B,0x50,0x7F,0x21,0x74,0xC1,0xBB,0xB8,0xB7,0xBA,
+ 0xB,0x35,0x95,0x31,0x59,0x9A,0x4D, 4, 7,0x1E,0x5A,0x76,0x13,0xF3,0x71,0x83,
+ 0xD0,0x86, 3,0xA8,0x39,0x42,0xAA,0x28,0xE6,0xE4,0xD8,0x5D,0xD3,0xD0,0x6E,0x6F,
+ 0x96,0xFB,0x5E,0xBC,0x56,0xC2,0x5F,0x85,0x9B,0xE7,0xAF,0xD2,0x3B,0x84,0x6A,0xA7,
+ 0x53,0xC5,0x44,0x49,0xA5,0xF9,0x36,0x72,0x3D,0x2C,0xD9,0x1B,0xA1,0xF5,0x4F,0x93,
+ 0x9D,0x68,0x47,0x41,0x16,0xCA,0x2A,0x4C,0xA3,0x87,0xD6,0xE5,0x19,0x2E,0x77,0x15,
+ 0x6D,0x70,0xC0,0xDF,0xB2, 0,0x46,0xED,0xC6,0x6C,0x43,0x60,0x92,0x2D,0xA9,0x22,
+ 0x45,0x8F,0x34,0x55,0xAE,0xA4, 0xA,0x66,0x32,0xE0,0xDC, 2,0xAC,0xE8,0x20,0x8C,
+ 0x89,0x62,0x4A,0xFE,0xEE,0xC3,0xE3,0x3C,0xF1,0x79, 5,0xE9,0xF6,0x27,0x33,0xCC,
+ 0xF2,0x9E,0x11,0x81,0x7E,0x80,0x10,0x8A,0x82,0x9F,0x48, 0xD,0xD7,0xB4,0xFC,0x2F,
+ 0xB5,0xC7,0xDD,0x88,0x14,0x6B,0x2B,0x54,0xEA,0x1D,0x94,0x5C,0xB0,0xEF,0x12,0x24,
+ 0xCD,0xEB,0xE1,0xE2,0x64,0x73,0x3F, 0xE,0x52,0x61,0x25,0x3E,0xF8, 0xF,0x4B,0xEC,
+ },
+ {
+ 0xC0, 0,0x30,0xF6, 2,0x49,0x3D,0x10,0x6E,0x20,0xC9,0xA6,0x2F,0xFE,0x2C,0x2B,
+ 0x75,0x2E,0x45,0x26,0xAB,0x48,0xA9,0x80,0xFC, 4,0xCC,0xD3,0xB5,0xBA,0xA3,0x38,
+ 0x31,0x7D, 1,0xD9,0xA7,0x7B,0x96,0xB6,0x63,0x69,0x4E,0xF7,0xDE,0xE0,0x78,0xCA,
+ 0x50,0xAA,0x41,0x91,0x65,0x88,0xE4,0x21,0x85,0xDA,0x3A,0x27,0xBE,0x1C,0x3E,0x42,
+ 0x5E,0x17,0x52,0x7F,0x1F,0x89,0x24,0x6F,0x8F,0x5C,0x67,0x74, 0xE,0x12,0x87,0x8D,
+ 0xE9,0x34,0xED,0x73,0xC4,0xF8,0x61,0x5B, 5,0xDF,0x59,0x4C,0x97,0x79,0x83,0x18,
+ 0xA4,0x55,0x95,0xEB,0xBD,0x53,0xF5,0xF1,0x57,0x66,0x46,0x9F,0xB2,0x81, 9,0x51,
+ 0x86,0x22,0x16,0xDD,0x23,0x93,0x76,0x29,0xC2,0xD7,0x1D,0xD4,0xBF,0x36,0x3F,0xEA,
+ 0x4B,0x11,0x32,0xB9,0x62,0x54,0x60,0xD6,0x6D,0x43,0x9A, 0xD,0x92,0x9C,0xB0,0xEF,
+ 0x58,0x6C,0x9D,0x77,0x2D,0x70,0xFA,0xF3,0xB3, 0xB,0xE2,0x40,0x7E,0xF4,0x8A,0xE5,
+ 0x8C,0x3C,0x56,0x71,0xD1,0x64,0xE1,0x82, 0xA,0xCB,0x13,0x15,0x90,0xEC, 3,0x99,
+ 0xAF,0x14,0x5D, 0xF,0x33,0x4A,0x94,0xA5,0xA8,0x35,0x1B,0xE3,0x6A,0xC6,0x28,0xFF,
+ 0x4D,0xE7,0x25,0x84,0xAC, 8,0xAE,0xC5,0xA2,0x2A,0xB8,0x37, 0xC,0x7A,0xA0,0xC3,
+ 0xCE,0xAD, 6,0x1A,0x9E,0x8B,0xFB,0xD5,0xD0,0xC1,0x1E,0xD0,0xB4,0x9B,0xB1,0x44,
+ 0xF2,0x47,0xC7,0x68,0xCF,0x72,0xBB,0x4F,0x5A,0xF9,0xDC,0x6B,0xDB,0xD2,0xE8,0x7C,
+ 0xC8,0xEE,0x98,0xA1,0xE6,0xD8,0x39, 7,0x5F,0xFD,0x8E,0x19,0xB7,0x3B,0xBC,0xCD,
+ },
+ {
+ 0x7C,0xE3,0x81,0x73,0xB2,0x11,0xBF,0x6F,0x20,0x98,0xFE,0x75,0x96,0xEF,0x6C,0xDA,
+ 0x50,0xE1, 9,0x72,0x54,0x45,0xBA,0x34,0x80,0x5B,0xED,0x3E,0x53,0x2C,0x87,0xA4,
+ 0x57,0xF3,0x33,0x3F,0x3C,0xB7,0x67,0xB4,0xA3,0x25,0x60,0x4F, 7,0x6B,0x1B,0x47,
+ 0x15, 0xF,0xE4, 0xA,0xEA,0xD1,0x32,0x78,0x36,0x49,0x8D,0x4B,0xD2,0xBC,0xA5,0xDC,
+ 0x1D, 0xD,0x4D,0xCD,0x9A,0x82,0x5F,0xFC,0x94,0x65,0xBE,0xE2,0xF4,0xC9,0x1E,0x44,
+ 0xCB,0x9E, 0xC,0x64,0x71,0x26,0x63,0xB3,0x14,0xE8,0x40,0x70,0x8A, 0xE,0x19,0x42,
+ 0x6D,0xAC,0x88,0x10,0x5C,0xDF,0x41,0xA9,0xAD,0xE5,0xFB,0x74,0xCC,0xD5, 6,0x8E,
+ 0x59,0x86,0xCE,0x1F,0x3D,0x76,0xE0,0x8F,0xB9,0x77,0x27,0x7B,0xA6,0xD8,0x29,0xD3,
+ 0xEC,0xB8,0x13,0xF7,0xFA,0xC3,0x51,0x6A,0xDE,0x4A,0x5A,0xEB,0xC2,0x8B,0x23,0x48,
+ 0x92,0xCF,0x62,0xA8,0x99,0xF8,0xD0,0x2E,0x85,0x61,0x43,0xC8,0xBD,0xF0, 5,0x93,
+ 0xCA,0x4E,0xF1,0x7D,0x30,0xFD,0xC4,0x69,0x66,0x2F, 8,0xB1,0x52,0xF9,0x21,0xE6,
+ 0x7A,0x2B,0xDD,0x39,0x84,0xFF,0xC0,0x91,0xD6,0x37,0xD4,0x7F,0x2D,0x9B,0x5D,0xA1,
+ 0x3B,0x6E,0xB5,0xC5,0x46, 4,0xF5,0x90,0xEE,0x7E,0x83,0x1C, 3,0x56,0xB6,0xAA,
+ 0,0x17, 1,0x35,0x55,0x79, 0xB,0x12,0xBB,0x1A,0x31,0xE7, 2,0x28,0x16,0xC1,
+ 0xF6,0xA2,0xDB,0x18,0x9C,0x89,0x68,0x38,0x97,0xAB,0xC7,0x2A,0xD7,0x3A,0xF2,0xC6,
+ 0x24,0x4C,0xB0,0x58,0xA0,0x22,0x5E,0x9D,0xD9,0xA7,0xE9,0xAE,0xAF,0x8C,0x95,0x9F,
+ },
+ {
+ 0x28,0xB7,0x20,0xD7,0xB0,0x30,0xC3, 9,0x19,0xC0,0x67,0xD6, 0,0x3C,0x7E,0xE7,
+ 0xE9,0xF4, 8,0x5A,0xF8,0xB8,0x2E, 5,0xA6,0x25,0x9E,0x5C,0xD8,0x15, 0xD,0xE1,
+ 0xF6,0x11,0x54,0x6B,0xCD,0x21,0x46,0x66,0x5E,0x84,0xAD, 6,0x38,0x29,0x44,0xC5,
+ 0xA2,0xCE,0xF1,0xAA,0xC1,0x40,0x71,0x86,0xB5,0xEF,0xFC,0x36,0xA8,0xCB, 0xA,0x48,
+ 0x27,0x45,0x64,0xA3,0xAF,0x8C,0xB2,0xC6,0x9F, 7,0x89,0xDC,0x17,0xD3,0x49,0x79,
+ 0xFB,0xFE,0x1D,0xD0,0xB9,0x88,0x43,0x52,0xBC, 1,0x78,0x2B,0x7D,0x94,0xC7, 0xE,
+ 0xDE,0xA5,0xD5,0x9B,0xCC,0xF7,0x61,0x7A,0xC2,0x74,0x81,0x39, 3,0xAB,0x96,0xA0,
+ 0x37,0xBD,0x2D,0x72,0x75,0x3F,0xC9,0xD4,0x8E,0x6F,0xF9,0x8D,0xED,0x62,0xDB,0x1C,
+ 0xDF, 4,0xAC,0x1B,0x6C,0x14,0x4B,0x63,0xD0,0xBF,0xB4,0x82,0xEC,0x7B,0x1A,0x59,
+ 0x92,0xD2,0x10,0x60,0xB6,0x3D,0x5F,0xE6,0x80,0x6E,0x70,0xC4,0xF2,0x35,0xD9,0x7C,
+ 0xEE,0xE5,0x41,0xA4,0x5B,0x50,0xDD,0xBB,0x4C,0xF3,0x1F,0x9D,0x5D,0x57,0x55,0x51,
+ 0x97,0xE3,0x58,0x42,0x4D,0x9C,0x73,0xBA,0xC8,0x77,0x31,0x69,0x26,0xAE,0xEA,0x8A,
+ 0xDA,0x22,0xB3,0x87,0x56,0xFA,0x93, 0xB,0x34,0x16,0x33,0xE8,0xE4,0x53,0xBE,0xA9,
+ 0xB1,0x3A,0x3E,0xF5,0x90,0x6A,0xCF,0x3B,0x12,0xFD,0x8F,0x9A,0xA7,0x47,0x91,0x99,
+ 0xEB, 0xF,0x24,0xFF,0x23,0x18,0x85,0x4E,0x7F, 0xC,0xE0,0xA1,0xD2,0xD1,0x2C,0x2A,
+ 0x4A, 2,0x4F,0x1E,0x95,0x68,0x8B,0x98,0x83,0x6D,0x76,0xCA,0x65,0x32,0x13,0x2F,
+ },
+ {
+ 0xC3,0x82,0x9A,0xA4,0xBA,0x81,0x60,0x37,0x34,0x35,0xFC,0x80,0xA8,0x51,0x65,0x67,
+ 0xED,0x30,0x5F,0x10,0xD3,0x4A,0x27,0x2F,0x13,0xB9,0x2A,0xD2,0xCC,0xE1,0xEF,0xAE,
+ 0xEB,0xBE,0xF4,0xBD,0xCF,0x43,0xB3,0xC5,0x88,0x84,0xB7,0xDD,0x39,0x40,0xCE,0x48,
+ 0x6D,0x9B,0x72,0x61,0x7E,0xE7,0xA1,0x4E,0x53,0x2E,0x77,0x3B,0xE2,0xC9,0x36,0x22,
+ 0x1B,0x6E,0x73,0xB1, 3,0xB2,0x4C,0x87,0xA9,0xD4,0x4D, 0xF,0xD8,0x15,0x6C,0xAA,
+ 0x18,0xF6,0x49,0x57,0x5D,0xFB,0x7A,0x14,0x94,0x63,0xA0,0x11,0xB0,0x9E,0xDE, 5,
+ 0x46,0xC8,0xEE,0x47,0xDB,0xDC,0x24,0x89,0x9C,0x91,0x97,0x29,0xE9,0x7B,0xC1, 7,
+ 0x1E,0xB8,0xFD,0xFE,0xAC,0xC6,0x62,0x98,0x4F,0xF1,0x79,0xE0,0xE8,0x6B,0x78,0x56,
+ 0xB6,0x8D, 4,0x50,0x86,0xCA,0x6F,0x20,0xE6,0xEA,0xE5,0x76,0x17,0x1C,0x74,0x7F,
+ 0xBC, 0xD,0x2C,0x85,0xF7,0x66,0x96,0xE4,0x8B,0x75,0x3F,0x4B,0xD9,0x38,0xAF,0x7C,
+ 0xDA, 0xB,0x83,0x2D,0x31,0x32,0xA2,0xF5,0x1D,0x59,0x41,0x45,0xBF,0x3C,0x1F,0xF8,
+ 0xF9,0x8A,0xD0,0x16,0x25,0x69,0x12,0x99,0x9D,0x21,0x95,0xAB, 1,0xA6,0xD7,0xB5,
+ 0xC0,0x7D,0xFF,0x58, 0xE,0x3A,0x92,0xD1,0x55,0xE3, 8,0x9F,0xD6,0x3E,0x52,0x8E,
+ 0xFA,0xA3,0xC7, 2,0xCD,0xDF,0x8F,0x64,0x19,0x8C,0xF3,0xA7, 0xC,0x5E, 0xA,0x6A,
+ 9,0xF0,0x93,0x5B,0x42,0xC2, 6,0x23,0xEC,0x71,0xAD,0xB4,0xCB,0xBB,0x70,0x28,
+ 0xD5,0x1A,0x5C,0x33,0x68,0x5A, 0,0x44,0x90,0xA5,0xC4,0x26,0x3D,0x2B,0xF2,0x54,
+ },
+ {
+ 0x96,0xAD,0xDA,0x1F,0xED,0x33,0xE1,0x81,0x69, 8, 0xD, 0xA,0xDB,0x35,0x77,0x9A,
+ 0x64,0xD1,0xFC,0x78,0xAA,0x1B,0xD0,0x67,0xA0,0xDD,0xFA,0x6C,0x63,0x71, 5,0x84,
+ 0x17,0x6A,0x89,0x4F,0x66,0x7F,0xC6,0x50,0x55,0x92,0x6F,0xBD,0xE7,0xD2,0x40,0x72,
+ 0x8D,0xBB,0xEC, 6,0x42,0x8A,0xE4,0x88,0x9D,0x7E,0x7A,0x82,0x27,0x13,0x41,0x1A,
+ 0xAF,0xC8,0xA4,0x76,0xB4,0xC2,0xFE,0x6D,0x1C,0xD9,0x61,0x30,0xB3,0x7C,0xEA,0xF7,
+ 0x29, 0xF,0xF2,0x3B,0x51,0xC1,0xDE,0x5F,0xE5,0x2A,0x2F,0x99, 0xB,0x5D,0xA3,0x2B,
+ 0x4A,0xAB,0x95,0xA5,0xD3,0x58,0x56,0xEE,0x28,0x31, 0,0xCC,0x15,0x46,0xCA,0xE6,
+ 0x86,0x38,0x3C,0x65,0xF5,0xE3,0x9F,0xD6,0x5B, 9,0x49,0x83,0x70,0x2D,0x53,0xA9,
+ 0x7D,0xE2,0xC4,0xAC,0x8E,0x5E,0xB8,0x25,0xF4,0xB9,0x57,0xF3,0xF1,0x68,0x47,0xB2,
+ 0xA2,0x59,0x20,0xCE,0x34,0x79,0x5C,0x90, 0xE,0x1E,0xBE,0xD5,0x22,0x23,0xB1,0xC9,
+ 0x18,0x62,0x16,0x2E,0x91,0x3E, 7,0x8F,0xD8,0x3F,0x93,0x3D,0xD4,0x9B,0xDF,0x85,
+ 0x21,0xFB,0x11,0x74,0x97,0xC7,0xD7,0xDC,0x4C,0x19,0x45,0x98,0xE9,0x43, 2,0x4B,
+ 0xBC,0xC3, 4,0x9C,0x6B,0xF0,0x75,0x52,0xA7,0x26,0xF6,0xC5,0xBA,0xCF,0xB0,0xB7,
+ 0xAE,0x5A,0xA1,0xBF, 3,0x8B,0x80,0x12,0x6E, 0xC,0xEB,0xF9,0xC0,0x44,0x24,0xEF,
+ 0x10,0xF8,0xA8,0x8C,0xE8,0x7B,0xFF,0x9E,0x2C,0xCD,0x60,0x36,0x87,0xB5,0x94,0xA6,
+ 0x54,0x73,0x3A,0x14,0x4E, 1,0x1D,0xB6,0xFD,0x37,0x48,0x4D,0x39,0xCB,0xE0,0x32,
+ }
+};
+
+
+static inline u8 ror8(u8 a, u8 b) {
+ return (a>>b) | ((a<<(8-b))&0xff);
+}
+
+
+void genkey(u8 *rand, u8 idx, u8 *key)
+{
+ u8 *ans = ans_tbl[idx];
+ u8 t0[10];
+ int i;
+
+ for(i=0;i<10;i++)
+ t0[i] = tsbox[rand[i]];
+
+ key[0] = ((ror8((ans[0]^t0[5]),(t0[2]%8)) - t0[9]) ^ t0[4]);
+ key[1] = ((ror8((ans[1]^t0[1]),(t0[0]%8)) - t0[5]) ^ t0[7]);
+ key[2] = ((ror8((ans[2]^t0[6]),(t0[8]%8)) - t0[2]) ^ t0[0]);
+ key[3] = ((ror8((ans[3]^t0[4]),(t0[7]%8)) - t0[3]) ^ t0[2]);
+ key[4] = ((ror8((ans[4]^t0[1]),(t0[6]%8)) - t0[3]) ^ t0[4]);
+ key[5] = ((ror8((ans[5]^t0[7]),(t0[8]%8)) - t0[5]) ^ t0[9]);
+}
+
+
+void gentabs(u8 *rand, u8 *key, u8 idx, u8 *ft, u8 *sb)
+{
+ ft[0] = sboxes[idx][key[4]] ^ sboxes[(idx+1)%8][rand[3]];
+ ft[1] = sboxes[idx][key[2]] ^ sboxes[(idx+1)%8][rand[5]];
+ ft[2] = sboxes[idx][key[5]] ^ sboxes[(idx+1)%8][rand[7]];
+ ft[3] = sboxes[idx][key[0]] ^ sboxes[(idx+1)%8][rand[2]];
+ ft[4] = sboxes[idx][key[1]] ^ sboxes[(idx+1)%8][rand[4]];
+ ft[5] = sboxes[idx][key[3]] ^ sboxes[(idx+1)%8][rand[9]];
+ ft[6] = sboxes[idx][rand[0]] ^ sboxes[(idx+1)%8][rand[6]];
+ ft[7] = sboxes[idx][rand[1]] ^ sboxes[(idx+1)%8][rand[8]];
+
+ sb[0] = sboxes[idx][key[0]] ^ sboxes[(idx+1)%8][rand[1]];
+ sb[1] = sboxes[idx][key[5]] ^ sboxes[(idx+1)%8][rand[4]];
+ sb[2] = sboxes[idx][key[3]] ^ sboxes[(idx+1)%8][rand[0]];
+ sb[3] = sboxes[idx][key[2]] ^ sboxes[(idx+1)%8][rand[9]];
+ sb[4] = sboxes[idx][key[4]] ^ sboxes[(idx+1)%8][rand[7]];
+ sb[5] = sboxes[idx][key[1]] ^ sboxes[(idx+1)%8][rand[8]];
+ sb[6] = sboxes[idx][rand[3]] ^ sboxes[(idx+1)%8][rand[5]];
+ sb[7] = sboxes[idx][rand[2]] ^ sboxes[(idx+1)%8][rand[6]];
+}
+
+
+
+
+// ===================================================
+/* Generate key from the 0x40-0x4c data in g_RegExt */
+// ----------------
+void wiimote_gen_key(wiimote_key *key, u8 *keydata)
+{
+ u8 rand[10];
+ u8 skey[6];
+ u8 testkey[6];
+ int idx;
+
+ for(int i=0;i<10;i++)
+ rand[9-i] = keydata[i];
+ for(int i=0;i<6;i++)
+ skey[5-i] = keydata[i+10];
+
+ INFO_LOG(CONSOLE, "rand: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", rand[0], rand[1], rand[2], rand[3], rand[4], rand[5], rand[6], rand[7], rand[8], rand[9]);
+ INFO_LOG(CONSOLE, "key: %02x %02x %02x %02x %02x %02x\n", skey[0], skey[1], skey[2], skey[3], skey[4], skey[5]);
+
+ for(idx = 0; idx < 7; idx++)
+ {
+ genkey(rand, idx, testkey);
+ if(!memcmp(testkey, skey, 6))
+ break;
+ }
+ // default case is idx = 7 which is valid (homebrew uses it for the 0x17 case)
+ INFO_LOG(CONSOLE, "idx: %d\n", idx);
+
+ gentabs(rand, skey, idx, key->ft, key->sb);
+
+ INFO_LOG(CONSOLE, "ft: %02x %02x %02x %02x %02x %02x %02x %02x\n", key->ft[0], key->ft[1], key->ft[2], key->ft[3], key->ft[4], key->ft[5], key->ft[6], key->ft[7]);
+ INFO_LOG(CONSOLE, "sb: %02x %02x %02x %02x %02x %02x %02x %02x\n", key->sb[0], key->sb[1], key->sb[2], key->sb[3], key->sb[4], key->sb[5], key->sb[6], key->sb[7]);
+
+ // for homebrew, ft and sb are all 0x97 which is equivalent to 0x17
+}
+
+
+// ===================================================
+/* Encrypt data */
+// ----------------
+void wiimote_encrypt(wiimote_key *key, u8 *data, int addr, u8 len)
+{
+ for(int i = 0; i < len; i++, addr++)
+ data[i] = (data[i] - key->ft[addr%8]) ^ key->sb[addr%8];
+}
+
+
+// ===================================================
+/* Decrypt data */
+// ----------------
+void wiimote_decrypt(wiimote_key *key, u8 *data, int addr, u8 len)
+{
+ for(int i = 0; i < len; i++, addr++)
+ data[i] = (data[i] ^ key->sb[addr%8]) + key->ft[addr%8];
+}
\ No newline at end of file
diff --git a/Source/Plugins/Plugin_Wiimote-testing/Src/Encryption.h b/Source/Plugins/Plugin_Wiimote-testing/Src/Encryption.h
new file mode 100644
index 0000000000..6322a57215
--- /dev/null
+++ b/Source/Plugins/Plugin_Wiimote-testing/Src/Encryption.h
@@ -0,0 +1,40 @@
+// Copyright (C) 2003-2008 Dolphin Project.
+// Copyright (C) Hector Martin "marcan" (hector@marcansoft.com)
+
+// 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 WIIMOTE_EXTENSION_ENCRYPTION_H
+#define WIIMOTE_EXTENSION_ENCRYPTION_H
+
+
+// ===================================================
+/* They key structure to use with wiimote_gen_key() */
+// ----------------
+typedef struct {
+ u8 ft[8];
+ u8 sb[8];
+} wiimote_key;
+
+
+void wiimote_encrypt(wiimote_key *key, u8 *data, int addr, u8 len);
+void wiimote_decrypt(wiimote_key *key, u8 *data, int addr, u8 len);
+
+void wiimote_gen_key(wiimote_key *key, u8 *keydata);
+
+
+#endif
+
diff --git a/Source/Plugins/Plugin_Wiimote-testing/Src/FillReport.cpp b/Source/Plugins/Plugin_Wiimote-testing/Src/FillReport.cpp
new file mode 100644
index 0000000000..885cc632bf
--- /dev/null
+++ b/Source/Plugins/Plugin_Wiimote-testing/Src/FillReport.cpp
@@ -0,0 +1,1374 @@
+// Copyright (C) 2003-2008 Dolphin Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official SVN repository and contact information can be found at
+// http://code.google.com/p/dolphin-emu/
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Includes
+// ŻŻŻŻŻŻŻŻŻŻŻŻŻ
+#include
+
+#include
+#include
+
+#include "Common.h" // Common
+#include "pluginspecs_wiimote.h"
+#include "StringUtil.h" // For ArrayToString
+
+#include "wiimote_hid.h"
+#include "main.h"
+#include "EmuMain.h"
+#include "EmuSubroutines.h"
+#include "EmuDefinitions.h"
+#include "Logging.h" // For startConsoleWin, Console::Print, GetConsoleHwnd
+#include "Config.h" // For g_Config
+//////////////////////////////////
+
+extern SWiimoteInitialize g_WiimoteInitialize;
+
+namespace WiiMoteEmu
+{
+
+
+//**************************************************************************************
+// Recorded movements
+//**************************************************************************************
+
+// ------------------------------------------
+// Variables: 0 = Wiimote, 1 = Nunchuck
+// ----------------
+int g_RecordingPlaying[3]; //g_RecordingPlaying[0] = -1; g_RecordingPlaying[1] = -1;
+int g_RecordingCounter[3]; //g_RecordingCounter[0] = 0; g_RecordingCounter[1] = 0;
+int g_RecordingPoint[3]; //g_RecordingPoint[0] = 0; g_RecordingPoint[1] = 0;
+double g_RecordingStart[3]; //g_RecordingStart[0] = 0; g_RecordingStart[1] = 0;
+double g_RecordingCurrentTime[3]; //g_RecordingCurrentTime[0] = 0; g_RecordingCurrentTime[1] = 0;
+// --------------------------
+
+/////////////////////////////////////////////////////////////////////////
+/* Convert from -350 to -3.5 g. The Nunchuck gravity size is 51 compared to the 26 to 28 for the Wiimote.
+ So the maximum g values are higher for the Wiimote. */
+// ---------------
+int G2Accelerometer(int _G, int XYZ, int Wm)
+{
+ float G = (float)_G / 100.0;
+ float Neutral, OneG, Accelerometer;
+
+ switch(XYZ)
+ {
+ case 0: // X
+ if(Wm == WM_RECORDING_WIIMOTE)
+ {
+ OneG = (float)g_wm.cal_g.x;
+ Neutral = (float)g_wm.cal_zero.x;
+ }
+ else
+ {
+ OneG = (float)g_nu.cal_g.x;
+ Neutral = (float)g_nu.cal_zero.x;
+ }
+ break;
+ case 1: // Y
+ if(Wm == WM_RECORDING_WIIMOTE)
+ {
+ OneG = (float)g_wm.cal_g.y;
+ Neutral = (float)g_wm.cal_zero.y;
+ }
+ else
+ {
+ OneG = (float)g_nu.cal_g.y;
+ Neutral = (float)g_nu.cal_zero.y;
+ }
+ break;
+ case 2: // Z
+ if(Wm == WM_RECORDING_WIIMOTE)
+ {
+ OneG = (float)g_wm.cal_g.z;
+ Neutral = (float)g_wm.cal_zero.z;
+ }
+ else
+ {
+ OneG = (float)g_nu.cal_g.z;
+ Neutral = (float)g_nu.cal_zero.z;
+ }
+ break;
+ default: PanicAlert("There is a syntax error in a function that is calling G2Accelerometer(%i, %i)", _G, XYZ);
+ }
+
+ Accelerometer = Neutral + (OneG * G);
+ int Return = (int)Accelerometer;
+
+ // Logging
+ //INFO_LOG(CONSOLE, "G2Accelerometer():%f %f %f %f\n", Neutral, OneG, G, Accelerometer);
+
+ // Boundaries
+ if (Return > 255) Return = 255;
+ if (Return < 0) Return = 0;
+
+ return Return;
+}
+
+template
+bool RecordingPlayAccIR(u8 &_x, u8 &_y, u8 &_z, IRReportType &_IR, int Wm)
+{
+ // Check if the recording is on
+ if (g_RecordingPlaying[Wm] == -1) return false;
+
+ // Return if the list is empty
+ if(VRecording.at(g_RecordingPlaying[Wm]).Recording.size() == 0)
+ {
+ g_RecordingPlaying[Wm] = -1;
+ INFO_LOG(CONSOLE, "Empty\n\n");
+ return false;
+ }
+
+ // Return if the playback speed is unset
+ if(VRecording.at(g_RecordingPlaying[Wm]).PlaybackSpeed < 0)
+ {
+ INFO_LOG(CONSOLE, "PlaybackSpeed empty: %i\n\n", g_RecordingPlaying[Wm]);
+ g_RecordingPlaying[Wm] = -1;
+ return false;
+ }
+
+ // Get IR bytes
+ int IRBytes = VRecording.at(g_RecordingPlaying[Wm]).IRBytes;
+
+ // Return if the IR mode is wrong
+ if (Wm == WM_RECORDING_IR
+ && ( (IRBytes == 12 && !(g_ReportingMode == 0x33))
+ || (IRBytes == 10 && !(g_ReportingMode == 0x36 || g_ReportingMode == 0x37))
+ )
+ )
+ {
+ INFO_LOG(CONSOLE, "Wrong IR mode: %i\n\n", g_RecordingPlaying[Wm]);
+ g_RecordingPlaying[Wm] = -1;
+ return false;
+ }
+
+ // Get starting time
+ if(g_RecordingCounter[Wm] == 0)
+ {
+ INFO_LOG(CONSOLE, "\n\nBegin: %i\n", Wm);
+ g_RecordingStart[Wm] = GetDoubleTime();
+ }
+
+ // Get current time
+ g_RecordingCurrentTime[Wm] = GetDoubleTime() - g_RecordingStart[Wm];
+
+ // Modify the current time
+ g_RecordingCurrentTime[Wm] *= ((25.0 + (double)VRecording.at(g_RecordingPlaying[Wm]).PlaybackSpeed * 25.0) / 100.0);
+
+ // Select reading
+ for (int i = 0; i < (int)VRecording.at(g_RecordingPlaying[Wm]).Recording.size(); i++)
+ if (VRecording.at(g_RecordingPlaying[Wm]).Recording.at(i).Time > g_RecordingCurrentTime[Wm])
+ {
+ g_RecordingPoint[Wm] = i;
+ break; // Break loop
+ }
+
+ // Return if we are at the end of the list
+ if(g_RecordingCurrentTime[Wm] >=
+ VRecording.at(g_RecordingPlaying[Wm]).Recording.at(
+ VRecording.at(g_RecordingPlaying[Wm]).Recording.size() - 1).Time)
+ // Or if we are playing back all observations regardless of time
+ //g_RecordingPoint[Wm] = g_RecordingCounter[Wm];
+ //if (g_RecordingPoint[Wm] >= VRecording.at(g_RecordingPlaying[Wm]).Recording.size())
+ {
+ g_RecordingCounter[Wm] = 0;
+ g_RecordingPlaying[Wm] = -1;
+ g_RecordingStart[Wm] = 0;
+ g_RecordingCurrentTime[Wm] = 0;
+ INFO_LOG(CONSOLE, "End: %i\n\n", Wm);
+ return false;
+ }
+
+ // Update accelerometer values
+ _x = G2Accelerometer(VRecording.at(g_RecordingPlaying[Wm]).Recording.at(g_RecordingPoint[Wm]).x, 0, Wm);
+ _y = G2Accelerometer(VRecording.at(g_RecordingPlaying[Wm]).Recording.at(g_RecordingPoint[Wm]).y, 1, Wm);
+ _z = G2Accelerometer(VRecording.at(g_RecordingPlaying[Wm]).Recording.at(g_RecordingPoint[Wm]).z, 2, Wm);
+ // Update IR values
+ if(Wm == WM_RECORDING_IR) memcpy(&_IR, VRecording.at(g_RecordingPlaying[Wm]).Recording.at(g_RecordingPoint[Wm]).IR, IRBytes);
+
+ if (g_DebugAccelerometer)
+ {
+ //Console::ClearScreen();
+ INFO_LOG(CONSOLE, "Current time: [%i / %i] %f %f\n",
+ g_RecordingPoint[Wm], VRecording.at(g_RecordingPlaying[Wm]).Recording.size(),
+ VRecording.at(g_RecordingPlaying[Wm]).Recording.at(g_RecordingPoint[Wm]).Time, g_RecordingCurrentTime[Wm]
+ );
+ INFO_LOG(CONSOLE, "Accel x, y, z: %03u %03u %03u\n", _x, _y, _z);
+ }
+ //INFO_LOG(CONSOLE, "Accel x, y, z: %03u %03u %03u\n", _x, _y, _z);
+
+ g_RecordingCounter[Wm]++;
+
+ return true;
+}
+/* Because the playback is neatly controlled by RecordingPlayAccIR() we use these functions to be able to
+ use RecordingPlayAccIR() for both accelerometer and IR recordings */
+bool RecordingPlay(u8 &_x, u8 &_y, u8 &_z, int Wm)
+{
+ wm_ir_basic IR;
+ return RecordingPlayAccIR(_x, _y, _z, IR, Wm);
+}
+template
+bool RecordingPlayIR(IRReportType &_IR)
+{
+ u8 x, y, z;
+ return RecordingPlayAccIR(x, y, z, _IR, 2);
+}
+
+// Return true if this particual numerical key is pressed
+bool IsNumericalKeyPressed(int _Key)
+{
+#ifdef _WIN32
+ // Check which key it is
+ std::string TmpKey = StringFromFormat("%i", _Key);
+ if(GetAsyncKeyState(TmpKey[0]))
+ return true;
+ else
+ // That numerical key is pressed
+ return false;
+#else
+ // TODO linux port
+ return false;
+#endif
+}
+
+// Check if a switch is pressed
+bool IsSwitchPressed(int _Key)
+{
+#ifdef _WIN32
+ // Check if that switch is pressed
+ switch (_Key)
+ {
+ case 0: if (GetAsyncKeyState(VK_SHIFT)) return true;
+ case 1: if (GetAsyncKeyState(VK_CONTROL)) return true;
+ case 2: if (GetAsyncKeyState(VK_MENU)) return true;
+ }
+
+ // That switch was not pressed
+ return false;
+#else
+ // TODO linux port
+ return false;
+#endif
+}
+
+// Check if we should start the playback of a recording. Once it has been started it can currently
+// not be stopped, it will always run to the end of the recording.
+int RecordingCheckKeys(int WmNuIr)
+{
+#ifdef _WIN32
+ //INFO_LOG(CONSOLE, "RecordingCheckKeys: %i\n", Wiimote);
+
+ // Check if we have a HotKey match
+ bool Match = false;
+ int Recording = -1;
+ for(int i = 0; i < RECORDING_ROWS; i++)
+ {
+ // Check all ten numerical keys
+ for(int j = 0; j < 10; j++)
+ {
+ if ((VRecording.at(i).HotKeyWiimote == j && WmNuIr == 0 && IsNumericalKeyPressed(j)
+ || VRecording.at(i).HotKeyNunchuck == j && WmNuIr == 1 && IsNumericalKeyPressed(j)
+ || VRecording.at(i).HotKeyIR == j && WmNuIr == 2 && IsNumericalKeyPressed(j))
+ && (IsSwitchPressed(VRecording.at(i).HotKeySwitch) || VRecording.at(i).HotKeySwitch == 3))
+ {
+ //INFO_LOG(CONSOLE, "Match: %i %i\n", i, Key);
+ Match = true;
+ Recording = i;
+ break;
+ }
+ }
+ }
+
+
+
+ // Return nothing if we don't have a match
+ if (!Match) return -1;
+
+ // Return the match
+ return Recording;
+#else
+ return -1;
+#endif
+}
+
+
+//******************************************************************************
+// Subroutines
+//******************************************************************************
+
+
+/////////////////////////////////////////////////////////////////////////
+// Multi System Input Status Check
+// ---------------
+int IsKey(int Key)
+{
+#ifdef _WIN32
+ switch(Key)
+ {
+ // Wiimote
+ case g_Wm.MA: return GetAsyncKeyState(VK_LBUTTON);
+ case g_Wm.MB: return GetAsyncKeyState(VK_RBUTTON);
+ case g_Wm.A: return GetAsyncKeyState(PadMapping[0].Wm.A);
+ case g_Wm.B: return GetAsyncKeyState(PadMapping[0].Wm.B);
+ case g_Wm.ONE: return GetAsyncKeyState(PadMapping[0].Wm.One);
+ case g_Wm.TWO: return GetAsyncKeyState(PadMapping[0].Wm.Two);
+ case g_Wm.P: return GetAsyncKeyState(PadMapping[0].Wm.P);
+ case g_Wm.M: return GetAsyncKeyState(PadMapping[0].Wm.M);
+ case g_Wm.H: return GetAsyncKeyState(PadMapping[0].Wm.H);
+ case g_Wm.L: return GetAsyncKeyState(PadMapping[0].Wm.L);
+ case g_Wm.R: return GetAsyncKeyState(PadMapping[0].Wm.R);
+ case g_Wm.U: return GetAsyncKeyState(PadMapping[0].Wm.U);
+ case g_Wm.D: return GetAsyncKeyState(PadMapping[0].Wm.D);
+ case g_Wm.PITCH_L: return GetAsyncKeyState(PadMapping[0].Wm.PitchL);
+ case g_Wm.PITCH_R: return GetAsyncKeyState(PadMapping[0].Wm.PitchR);
+ case g_Wm.SHAKE: return GetAsyncKeyState(PadMapping[0].Wm.Shake);
+
+ // Nunchuck
+ case g_Nc.Z: return GetAsyncKeyState(PadMapping[0].Nc.Z);
+ case g_Nc.C: return GetAsyncKeyState(PadMapping[0].Nc.C);
+ case g_Nc.L: return GetAsyncKeyState(PadMapping[0].Nc.L);
+ case g_Nc.R: return GetAsyncKeyState(PadMapping[0].Nc.R);
+ case g_Nc.U: return GetAsyncKeyState(PadMapping[0].Nc.U);
+ case g_Nc.D: return GetAsyncKeyState(PadMapping[0].Nc.D);
+ case g_Nc.SHAKE: return GetAsyncKeyState(PadMapping[0].Nc.Shake);
+
+ // Classic Controller
+ case g_Cc.A: return GetAsyncKeyState(PadMapping[0].Cc.A);
+ case g_Cc.B: return GetAsyncKeyState(PadMapping[0].Cc.B);
+ case g_Cc.X: return GetAsyncKeyState(PadMapping[0].Cc.X);
+ case g_Cc.Y: return GetAsyncKeyState(PadMapping[0].Cc.Y);
+ case g_Cc.P: return GetAsyncKeyState(PadMapping[0].Cc.P); // Default is O instead of P
+ case g_Cc.M: return GetAsyncKeyState(PadMapping[0].Cc.M); // Default is N instead of M
+ case g_Cc.H: return GetAsyncKeyState(PadMapping[0].Cc.H); // Default is U instead of H
+
+ case g_Cc.Tl: return GetAsyncKeyState(PadMapping[0].Cc.Tl); // Digital left trigger
+ case g_Cc.Zl: return GetAsyncKeyState(PadMapping[0].Cc.Zl);
+ case g_Cc.Zr: return GetAsyncKeyState(PadMapping[0].Cc.Zr);
+ case g_Cc.Tr: return GetAsyncKeyState(PadMapping[0].Cc.Tr); // Digital right trigger
+
+ case g_Cc.Dl: return GetAsyncKeyState(PadMapping[0].Cc.Dl); // Digital left
+ case g_Cc.Du: return GetAsyncKeyState(PadMapping[0].Cc.Du); // Up
+ case g_Cc.Dr: return GetAsyncKeyState(PadMapping[0].Cc.Dr); // Right
+ case g_Cc.Dd: return GetAsyncKeyState(PadMapping[0].Cc.Dd); // Down
+
+ case g_Cc.Ll: return GetAsyncKeyState(PadMapping[0].Cc.Ll); // Left analog
+ case g_Cc.Lu: return GetAsyncKeyState(PadMapping[0].Cc.Lu);
+ case g_Cc.Lr: return GetAsyncKeyState(PadMapping[0].Cc.Lr);
+ case g_Cc.Ld: return GetAsyncKeyState(PadMapping[0].Cc.Ld);
+
+ case g_Cc.Rl: return GetAsyncKeyState(PadMapping[0].Cc.Rl); // Right analog
+ case g_Cc.Ru: return GetAsyncKeyState(PadMapping[0].Cc.Ru);
+ case g_Cc.Rr: return GetAsyncKeyState(PadMapping[0].Cc.Rr);
+ case g_Cc.Rd: return GetAsyncKeyState(PadMapping[0].Cc.Rd);
+
+ // This should not happen
+ default: PanicAlert("There is syntax error in a function that is calling IsKey(%i)", Key); return false;
+ }
+#else
+ return false;
+#endif
+}
+//////////////////////////////////////////
+
+
+/////////////////////////////////////////////////////////////////////////
+// Wiimote core buttons
+// ---------------
+void FillReportInfo(wm_core& _core)
+{
+ /* This has to be filled with zeroes (and not for example 0xff) because when no buttons are pressed the
+ value is 00 00 */
+ memset(&_core, 0x00, sizeof(wm_core));
+
+ // Check that Dolphin is in focus
+ if (!IsFocus()) return;
+
+ // Check the mouse position. Don't allow mouse clicks from outside the window.
+ float x, y; GetMousePos(x, y);
+ bool InsideScreen = !(x < 0 || x > 1 || y < 0 || y > 1);
+
+ // Allow both mouse buttons and keyboard to press a and b
+ if((IsKey(g_Wm.MA) && InsideScreen) || IsKey(g_Wm.A))
+ _core.a = 1;
+ if((IsKey(g_Wm.MB) && InsideScreen) || IsKey(g_Wm.B))
+ _core.b = 1;
+
+ _core.one = IsKey(g_Wm.ONE) ? 1 : 0;
+ _core.two = IsKey(g_Wm.TWO) ? 1 : 0;
+ _core.plus = IsKey(g_Wm.P) ? 1 : 0;
+ _core.minus = IsKey(g_Wm.M) ? 1 : 0;
+ _core.home = IsKey(g_Wm.H) ? 1 : 0;
+
+ /* Sideways controls (for example for Wario Land) if the Wiimote is intended to be held sideways */
+ if(g_Config.bSidewaysDPad)
+ {
+ _core.left = IsKey(g_Wm.D) ? 1 : 0;
+ _core.up = IsKey(g_Wm.L) ? 1 : 0;
+ _core.right = IsKey(g_Wm.U) ? 1 : 0;
+ _core.down = IsKey(g_Wm.R) ? 1 : 0;
+ }
+ else
+ {
+ _core.left = IsKey(g_Wm.L) ? 1 : 0;
+ _core.up = IsKey(g_Wm.U) ? 1 : 0;
+ _core.right = IsKey(g_Wm.R) ? 1 : 0;
+ _core.down = IsKey(g_Wm.D) ? 1 : 0;
+ }
+}
+//////////////////////////
+
+
+///////////////////////////////////////////////////////////////////
+// Wiimote accelerometer
+// ---------------
+/* The accelerometer x, y and z values range from 0x00 to 0xff with the default netural values
+ being [y = 0x84, x = 0x84, z = 0x9f] according to a source. The extremes are 0x00 for (-)
+ and 0xff for (+). It's important that all values are not 0x80, the mouse pointer can disappear
+ from the screen permanently then, until z is adjusted back. This is because the game detects
+ a steep pitch of the Wiimote then. */
+
+
+// ----------
+// Global declarations for FillReportAcc: These variables are global so they can be changed during debugging
+//int A = 0, B = 128, C = 64; // for debugging
+//int a = 1, b = 1, c = 2, d = -2; // for debugging
+//int consoleDisplay = 0;
+
+// For all functions
+u8 g_x, g_y, g_z, g_X, g_Y, g_Z;
+
+// For the shake function, 0 = Wiimote, 1 = Nunchuck
+int Shake[] = {-1, -1};
+
+// For the tilt function, the size of this list determines how fast Y returns to its neutral value
+std::vector yhist(15, 0); float KbDegree;
+
+
+// ------------------------------------------
+// Single shake of Wiimote while holding it sideways (Wario Land pound ground)
+// ---------------
+void SingleShake(u8 &_y, u8 &_z, int i)
+{
+#ifdef _WIN32
+ // Shake Wiimote with S, Nunchuck with D
+ if((i == 0 && IsKey(g_Wm.SHAKE)) || (i == 1 && IsKey(g_Nc.SHAKE)))
+ {
+ _z = 0;
+ _y = 0;
+ Shake[i] = 2;
+ }
+ else if(Shake[i] == 2)
+ {
+ // This works regardless of calibration, in Wario Land
+ _z = g_wm.cal_zero.z - 2;
+ _y = 0;
+ Shake[i] = 1;
+ }
+ else if(Shake[i] == 1)
+ {
+ Shake[i] = -1;
+ }
+#endif
+ //if (Shake[i] > -1) INFO_LOG(CONSOLE, "Shake: %i\n", Shake[i]);
+}
+
+
+// ------------------------------------------
+/* Tilting Wiimote with gamepad. We can guess that the game will calculate a Wiimote pitch and use it as a
+ measure of the tilting of the Wiimote. We are interested in this tilting range
+ 90° to -90° */
+// ---------------
+void TiltWiimoteGamepad(float &Roll, float &Pitch)
+{
+ // Return if we have no pads
+ if (NumGoodPads == 0) return;
+
+ // This has to be changed if multiple Wiimotes are to be supported later
+ const int Page = 0;
+
+ /* Adjust the pad state values, including a downscaling from the original 0x8000 size values
+ to 0x80. The only reason we do this is that the code below crrently assume that the range
+ is 0 to 255 for all axes. If we lose any precision by doing this we could consider not
+ doing this adjustment. And instead for example upsize the XInput trigger from 0x80 to 0x8000. */
+ int _Lx, _Ly, _Rx, _Ry, _Tl, _Tr;
+ PadStateAdjustments(_Lx, _Ly, _Rx, _Ry, _Tl, _Tr);
+ float Lx = (float)_Lx;
+ float Ly = (float)_Ly;
+ float Rx = (float)_Rx;
+ float Ry = (float)_Ry;
+ float Tl = (float)_Tl;
+ float Tr = (float)_Tr;
+
+ // Save the Range in degrees, 45° and 90° are good values in some games
+ float RollRange = (float)g_Config.Trigger.Range.Roll;
+ float PitchRange = (float)g_Config.Trigger.Range.Pitch;
+
+ // The trigger currently only controls pitch
+ if (g_Config.Trigger.Type == g_Config.Trigger.TRIGGER)
+ {
+ // Make the range the same dimension as the analog stick
+ Tl = Tl / 2;
+ Tr = Tr / 2;
+ // Invert
+ if (PadMapping[Page].bPitchInvert) { Tl = -Tl; Tr = -Tr; }
+ // The final value
+ Pitch = Tl * (PitchRange / 128.0)
+ - Tr * (PitchRange / 128.0);
+ }
+
+ /* For the analog stick roll us by default set to the X-axis, pitch is by default set to the Y-axis.
+ By changing the axis mapping and the invert options this can be altered in any way */
+ else if (g_Config.Trigger.Type == g_Config.Trigger.ANALOG1)
+ {
+ // Adjust the trigger to go between negative and positive values
+ Lx = Lx - 128.0;
+ Ly = Ly - 128.0;
+ // Invert
+ if (PadMapping[Page].bRollInvert) Lx = -Lx; // else Tr = -Tr;
+ if (PadMapping[Page].bPitchInvert) Ly = -Ly; // else Tr = -Tr;
+ // Produce the final value
+ Roll = Lx * (RollRange / 128.0);
+ Pitch = Ly * (PitchRange / 128.0);
+ }
+ // Otherwise we are using ANALOG2
+ else
+ {
+ // Adjust the trigger to go between negative and positive values
+ Rx = Rx - 128.0;
+ Ry = Ry - 128.0;
+ // Invert
+ if (PadMapping[Page].bRollInvert) Rx = -Rx; // else Tr = -Tr;
+ if (PadMapping[Page].bPitchInvert) Ry = -Ry; // else Tr = -Tr;
+ // Produce the final value
+ Roll = Rx * (RollRange / 128.0);
+ Pitch = Ry * (PitchRange / 128.0);
+ }
+
+ // Adjustment to prevent a slightly to high angle
+ if (Pitch >= PitchRange) Pitch = PitchRange - 0.1;
+ if (Roll >= RollRange) Roll = RollRange - 0.1;
+}
+
+
+// ------------------------------------------
+// Tilting Wiimote with keyboard
+// ---------------
+void TiltWiimoteKeyboard(float &Roll, float &Pitch)
+{
+#ifdef _WIN32
+ if(IsKey(g_Wm.PITCH_L))
+ {
+ // Stop at the upper end of the range
+ if(KbDegree < g_Config.Trigger.Range.Pitch)
+ KbDegree += 3; // aim left
+ }
+ else if(IsKey(g_Wm.PITCH_R))
+ {
+ // Stop at the lower end of the range
+ if(KbDegree > -g_Config.Trigger.Range.Pitch)
+ KbDegree -= 3; // aim right
+ }
+
+ // -----------------------------------
+ // Check for inactivity in the tilting, the Y value will be reset after ten inactive updates
+ // ----------
+ // Check for activity
+ yhist[yhist.size() - 1] = (
+ IsKey(g_Wm.PITCH_L)
+ ||IsKey(g_Wm.PITCH_R)
+ );
+
+ // Move all items back, and check if any of them are true
+ bool ypressed = false;
+ for (int i = 1; i < (int)yhist.size(); i++)
+ {
+ yhist[i-1] = yhist[i];
+ if(yhist[i]) ypressed = true;
+ }
+ // Tilting was not used a single time, reset the angle to zero
+ if(!ypressed)
+ {
+ KbDegree = 0;
+ }
+ else
+ {
+ Pitch = KbDegree;
+ //INFO_LOG(CONSOLE, "Degree: %2.1f\n", KbDegree);
+ }
+ // --------------------
+#endif
+}
+
+// ------------------------------------------
+// Tilting Wiimote (Wario Land aiming, Mario Kart steering and other things)
+// ---------------
+void Tilt(u8 &_x, u8 &_y, u8 &_z)
+{
+ // Ceck if it's on
+ if (g_Config.Trigger.Type == g_Config.Trigger.TRIGGER_OFF) return;
+
+ // Set to zero
+ float Roll = 0, Pitch = 0;
+
+ // Select input method and return the x, y, x values
+ if (g_Config.Trigger.Type == g_Config.Trigger.KEYBOARD)
+ TiltWiimoteKeyboard(Roll, Pitch);
+ else if (g_Config.Trigger.Type == g_Config.Trigger.TRIGGER || g_Config.Trigger.Type == g_Config.Trigger.ANALOG1 || g_Config.Trigger.Type == g_Config.Trigger.ANALOG2)
+ TiltWiimoteGamepad(Roll, Pitch);
+
+ // Adjust angles, it's only needed if both roll and pitch is used together
+ if (g_Config.Trigger.Range.Roll != 0 && g_Config.Trigger.Range.Pitch != 0) AdjustAngles(Roll, Pitch);
+
+ // Calculate the accelerometer value from this tilt angle
+ //PitchDegreeToAccelerometer(Roll, Pitch, _x, _y, _z, g_Config.Trigger.Roll, g_Config.Trigger.Pitch);
+ PitchDegreeToAccelerometer(Roll, Pitch, _x, _y, _z);
+
+ if (g_DebugData)
+ {
+ //Console::ClearScreen();
+ /*INFO_LOG(CONSOLE, "L:%2.1f R:%2.1f Lx:%2.1f Range:%2.1f Degree:%2.1f L:%i R:%i\n",
+ Tl, Tr, Lx, Range, Degree, PadState[Page].Axis.Tl, PadState[Page].Axis.Tr);*/
+ /*INFO_LOG(CONSOLE, "Roll:%2.1f Pitch:%2.1f\n", Roll, Pitch);*/
+ }
+}
+
+void FillReportAcc(wm_accel& _acc)
+{
+ // ------------------------------------
+ // Recorded movements
+ // --------------
+ // Check for a playback command
+ if(g_RecordingPlaying[0] < 0)
+ {
+ g_RecordingPlaying[0] = RecordingCheckKeys(0);
+ }
+ else
+ {
+ // If the recording reached the end or failed somehow we will not return
+ if (RecordingPlay(_acc.x, _acc.y, _acc.z, 0)) return;
+ //INFO_LOG(CONSOLE, "X, Y, Z: %u %u %u\n", _acc.x, _acc.y, _acc.z);
+ }
+ // ---------------------
+
+ // The default values can change so we need to update them all the time
+ g_X = g_wm.cal_zero.x;
+ g_Y = g_wm.cal_zero.y;
+ g_Z = g_wm.cal_zero.z + g_wm.cal_g.z;
+
+
+ // Check that Dolphin is in focus
+ if (!IsFocus())
+ {
+ _acc.x = g_X;
+ _acc.y = g_y;
+ _acc.z = g_z;
+ return;
+ }
+
+ // ------------------------------------------------
+ // Wiimote to Gamepad translations
+ // ------------
+
+ // The following functions may or may not update these values
+ g_x = g_X;
+ g_y = g_Y;
+ g_z = g_Z;
+
+ // Shake the Wiimote
+ SingleShake(g_y, g_z, 0);
+
+ // Tilt Wiimote, allow the shake function to interrupt it
+ if (Shake[0] == -1) Tilt(g_x, g_y, g_z);
+
+ // Write final values
+ _acc.x = g_x;
+ _acc.y = g_y;
+ _acc.z = g_z;
+
+
+ // ----------------------------
+ // Debugging for translating Wiimote to Keyboard (or Gamepad)
+ // ----------
+ /*
+
+ // Toogle console display
+ if(GetAsyncKeyState('U'))
+ {
+ if(consoleDisplay < 2)
+ consoleDisplay ++;
+ else
+ consoleDisplay = 0;
+ }
+
+ if(GetAsyncKeyState('5'))
+ A-=1;
+ else if(GetAsyncKeyState('6'))
+ A+=1;
+ if(GetAsyncKeyState('7'))
+ B-=1;
+ else if(GetAsyncKeyState('8'))
+ B+=1;
+ if(GetAsyncKeyState('9'))
+ C-=1;
+ else if(GetAsyncKeyState('0'))
+ C+=1;
+
+ else if(GetAsyncKeyState(VK_NUMPAD3))
+ d-=1;
+ else if(GetAsyncKeyState(VK_NUMPAD6))
+ d+=1;
+ else if(GetAsyncKeyState(VK_ADD))
+ yhistsize-=1;
+ else if(GetAsyncKeyState(VK_SUBTRACT))
+ yhistsize+=1;
+
+
+ if(GetAsyncKeyState(VK_INSERT))
+ AX-=1;
+ else if(GetAsyncKeyState(VK_DELETE))
+ AX+=1;
+ else if(GetAsyncKeyState(VK_HOME))
+ AY-=1;
+ else if(GetAsyncKeyState(VK_END))
+ AY+=1;
+ else if(GetAsyncKeyState(VK_SHIFT))
+ AZ-=1;
+ else if(GetAsyncKeyState(VK_CONTROL))
+ AZ+=1;
+
+ if(GetAsyncKeyState(VK_NUMPAD1))
+ X+=1;
+ else if(GetAsyncKeyState(VK_NUMPAD2))
+ X-=1;
+ if(GetAsyncKeyState(VK_NUMPAD4))
+ Y+=1;
+ else if(GetAsyncKeyState(VK_NUMPAD5))
+ Y-=1;
+ if(GetAsyncKeyState(VK_NUMPAD7))
+ Z+=1;
+ else if(GetAsyncKeyState(VK_NUMPAD8))
+ Z-=1;
+
+
+ //if(consoleDisplay == 0)
+ INFO_LOG(CONSOLE, "x: %03i | y: %03i | z: %03i | A:%i B:%i C:%i a:%i b:%i c:%i d:%i X:%i Y:%i Z:%i\n",
+ _acc.x, _acc.y, _acc.z,
+ A, B, C,
+ a, b, c, d,
+ X, Y, Z
+ );
+ INFO_LOG(CONSOLE, "x: %03i | y: %03i | z: %03i | X:%i Y:%i Z:%i | AX:%i AY:%i AZ:%i \n",
+ _acc.x, _acc.y, _acc.z,
+ X, Y, Z,
+ AX, AY, AZ
+ );*/
+}
+/////////////////////////
+
+
+
+
+/*
+ int Top = TOP, Left = LEFT, Right = RIGHT,
+ Bottom = BOTTOM, SensorBarRadius = SENSOR_BAR_RADIUS;
+*/
+
+///////////////////////////////////////////////////////////////////
+// The extended 12 byte (3 byte per object) reporting
+// ---------------
+void FillReportIR(wm_ir_extended& _ir0, wm_ir_extended& _ir1)
+{
+ // ------------------------------------
+ // Recorded movements
+ // --------------
+ // Check for a playback command
+ if(g_RecordingPlaying[2] < 0)
+ {
+ g_RecordingPlaying[2] = RecordingCheckKeys(2);
+ }
+ else
+ {
+ //INFO_LOG(CONSOLE, "X, Y, Z: %u %u %u\n", _acc.x, _acc.y, _acc.z);
+ if (RecordingPlayIR(_ir0)) return;
+ }
+ // ---------------------
+
+ /* Fill with 0xff if empty. The real Wiimote seems to use 0xff when it doesn't see a certain point,
+ at least from how WiiMoteReal::SendEvent() works. */
+ memset(&_ir0, 0xff, sizeof(wm_ir_extended));
+ memset(&_ir1, 0xff, sizeof(wm_ir_extended));
+
+ float MouseX, MouseY;
+ GetMousePos(MouseX, MouseY);
+
+ // If we are outside the screen leave the values at 0xff
+ if(MouseX > 1 || MouseX < 0 || MouseY > 1 || MouseY < 0) return;
+
+ // --------------------------------------
+ // Position calculation
+ // ----------
+ int y0 = g_Config.iIRTop + (MouseY * g_Config.iIRHeight);
+ int y1 = y0;
+ // The distance between the x positions are two sensor bar radii
+ int x0 = g_Config.iIRLeft + (MouseX * g_Config.iIRWidth) - SENSOR_BAR_RADIUS;
+ int x1 = g_Config.iIRLeft + (MouseX * g_Config.iIRWidth) + SENSOR_BAR_RADIUS;
+ // ------------------
+
+ // ----------------------------
+ // Debugging for calibration
+ // ----------
+ /*
+ if(!GetAsyncKeyState(VK_CONTROL) && GetAsyncKeyState(VK_RIGHT))
+ Right +=1;
+ else if(GetAsyncKeyState(VK_CONTROL) && GetAsyncKeyState(VK_RIGHT))
+ Right -=1;
+ if(!GetAsyncKeyState(VK_CONTROL) && GetAsyncKeyState(VK_LEFT))
+ Left +=1;
+ else if(GetAsyncKeyState(VK_CONTROL) && GetAsyncKeyState(VK_LEFT))
+ Left -=1;
+ if(!GetAsyncKeyState(VK_CONTROL) && GetAsyncKeyState(VK_UP))
+ Top += 1;
+ else if(GetAsyncKeyState(VK_CONTROL) && GetAsyncKeyState(VK_UP))
+ Top -= 1;
+ if(!GetAsyncKeyState(VK_CONTROL) && GetAsyncKeyState(VK_DOWN))
+ Bottom += 1;
+ else if(GetAsyncKeyState(VK_CONTROL) && GetAsyncKeyState(VK_DOWN))
+ Bottom -= 1;
+ if(!GetAsyncKeyState(VK_CONTROL) && GetAsyncKeyState(VK_NUMPAD0))
+ SensorBarRadius += 1;
+ else if(GetAsyncKeyState(VK_CONTROL) && GetAsyncKeyState(VK_NUMPAD0))
+ SensorBarRadius -= 1;
+
+ //Console::ClearScreen();
+ //if(consoleDisplay == 1)
+ INFO_LOG(CONSOLE, "x0:%03i x1:%03i y0:%03i y1:%03i | T:%i L:%i R:%i B:%i S:%i\n",
+ x0, x1, y0, y1, Top, Left, Right, Bottom, SensorBarRadius
+ );*/
+ // ------------------
+
+
+ // --------------------------------------
+ // Converted to IR data
+ // ----------
+ // The width is 0 to 1023
+ // The height is 0 to 767
+ x0 = 1023 - x0;
+ _ir0.x = x0 & 0xff; _ir0.xHi = x0 >> 8;
+ _ir0.y = y0 & 0xff; _ir0.yHi = y0 >> 8;
+ // The size can be between 0 and 15 and is probably not important
+ _ir0.size = 10;
+
+ x1 = 1023 - x1;
+ _ir1.x = x1 & 0xff; _ir1.xHi = x1 >> 8;
+ _ir1.y = y1 & 0xff; _ir1.yHi = y1 >> 8;
+ _ir1.size = 10;
+ // ------------------
+}
+
+///////////////////////////////////////////////////////////////////
+// The 10 byte reporting used when an extension is connected
+// ---------------
+void FillReportIRBasic(wm_ir_basic& _ir0, wm_ir_basic& _ir1)
+{
+
+ // ------------------------------------
+ // Recorded movements
+ // --------------
+ // Check for a playback command
+ if(g_RecordingPlaying[2] < 0)
+ {
+ g_RecordingPlaying[2] = RecordingCheckKeys(2);
+ }
+ // We are playing back a recording, we don't accept any manual input this time
+ else
+ {
+ //INFO_LOG(CONSOLE, "X, Y, Z: %u %u %u\n", _acc.x, _acc.y, _acc.z);
+ if (RecordingPlayIR(_ir0)) return;
+ }
+ // ---------------------
+
+ // Fill with 0xff if empty
+ memset(&_ir0, 0xff, sizeof(wm_ir_basic));
+ memset(&_ir1, 0xff, sizeof(wm_ir_basic));
+
+ float MouseX, MouseY;
+ GetMousePos(MouseX, MouseY);
+
+ // If we are outside the screen leave the values at 0xff
+ if(MouseX > 1 || MouseX < 0 || MouseY > 1 || MouseY < 0) return;
+
+ int y1 = g_Config.iIRTop + (MouseY * g_Config.iIRHeight);
+ int y2 = g_Config.iIRTop + (MouseY * g_Config.iIRHeight);
+
+ int x1 = g_Config.iIRLeft + (MouseX * g_Config.iIRWidth) - SENSOR_BAR_RADIUS;
+ int x2 = g_Config.iIRLeft + (MouseX * g_Config.iIRWidth) + SENSOR_BAR_RADIUS;
+
+ /* As with the extented report we settle with emulating two out of four possible objects
+ the only difference is that we don't report any size of the tracked object here */
+ x1 = 1023 - x1;
+ _ir0.x1 = x1 & 0xff; _ir0.x1Hi = (x1 >> 8); // we are dealing with 2 bit values here
+ _ir0.y1 = y1 & 0xff; _ir0.y1Hi = (y1 >> 8);
+
+ x2 = 1023 - x2;
+ _ir0.x2 = x2 & 0xff; _ir0.x2Hi = (x2 >> 8);
+ _ir0.y2 = y2 & 0xff; _ir0.y2Hi = (y2 >> 8);
+
+
+ // ------------------------------------
+ // Debugging for calibration
+ // ----------
+ /*
+ if(GetAsyncKeyState(VK_NUMPAD1))
+ Right +=1;
+ else if(GetAsyncKeyState(VK_NUMPAD2))
+ Right -=1;
+ if(GetAsyncKeyState(VK_NUMPAD4))
+ Left +=1;
+ else if(GetAsyncKeyState(VK_NUMPAD5))
+ Left -=1;
+ if(GetAsyncKeyState(VK_NUMPAD7))
+ Top += 1;
+ else if(GetAsyncKeyState(VK_NUMPAD8))
+ Top -= 1;
+ if(GetAsyncKeyState(VK_NUMPAD6))
+ Bottom += 1;
+ else if(GetAsyncKeyState(VK_NUMPAD3))
+ Bottom -= 1;
+ if(GetAsyncKeyState(VK_INSERT))
+ SensorBarRadius += 1;
+ else if(GetAsyncKeyState(VK_DELETE))
+ SensorBarRadius -= 1;
+
+ //ClearScreen();
+ //if(consoleDisplay == 1)
+
+ INFO_LOG(CONSOLE, "x1:%03i x2:%03i y1:%03i y2:%03i irx1:%02x y1:%02x x2:%02x y2:%02x | T:%i L:%i R:%i B:%i S:%i\n",
+ x1, x2, y1, y2, _ir0.x1, _ir0.y1, _ir1.x2, _ir1.y2, Top, Left, Right, Bottom, SensorBarRadius
+ );
+ INFO_LOG(CONSOLE, "\n");
+ INFO_LOG(CONSOLE, "ir0.x1:%02x x1h:%02x x2:%02x x2h:%02x | ir0.y1:%02x y1h:%02x y2:%02x y2h:%02x | ir1.x1:%02x x1h:%02x x2:%02x x2h:%02x | ir1.y1:%02x y1h:%02x y2:%02x y2h:%02x\n",
+ _ir0.x1, _ir0.x1Hi, _ir0.x2, _ir0.x2Hi,
+ _ir0.y1, _ir0.y1Hi, _ir0.y2, _ir0.y2Hi,
+ _ir1.x1, _ir1.x1Hi, _ir1.x2, _ir1.x2Hi,
+ _ir1.y1, _ir1.y1Hi, _ir1.y2, _ir1.y2Hi
+ );*/
+ // ------------------
+}
+
+
+//**************************************************************************************
+// Extensions
+//**************************************************************************************
+
+
+// ===================================================
+/* Generate the 6 byte extension report for the Nunchuck, encrypted. The bytes are JX JY AX AY AZ BT. */
+// ----------------
+void FillReportExtension(wm_extension& _ext)
+{
+ // ------------------------------------------
+ // Recorded movements
+ // --------------
+ // Check for a playback command
+ if(g_RecordingPlaying[1] < 0) g_RecordingPlaying[1] = RecordingCheckKeys(1);
+
+ // We should not play back the accelerometer values
+ if (!(g_RecordingPlaying[1] >= 0 && RecordingPlay(_ext.ax, _ext.ay, _ext.az, 1)))
+ {
+ // Use the neutral values
+ _ext.ax = g_nu.cal_zero.x;
+ _ext.ay = g_nu.cal_zero.y;
+ _ext.az = g_nu.cal_zero.z + g_nu.cal_g.z;
+ }
+ // ---------------------
+
+ // Shake the Wiimote
+ SingleShake(_ext.ay, _ext.az, 1);
+
+ // ------------------------------------
+ // The default joystick and button values unless we use them
+ // --------------
+ _ext.jx = g_nu.jx.center;
+ _ext.jy = g_nu.jy.center;
+ _ext.bt = 0x03; // 0x03 means no button pressed, the button is zero active
+ // ---------------------
+
+ // Update the analog stick
+ if (g_Config.Nunchuck.Type == g_Config.Nunchuck.KEYBOARD)
+ {
+ // Set the max values to the current calibration values
+ if(IsKey(g_Nc.L)) // x
+ _ext.jx = g_nu.jx.min;
+ if(IsKey(g_Nc.R))
+ _ext.jx = g_nu.jx.max;
+
+ if(IsKey(g_Nc.D)) // y
+ _ext.jy = g_nu.jy.min;
+ if(IsKey(g_Nc.U))
+ _ext.jy = g_nu.jy.max;
+ }
+ else
+ {
+ // Get adjusted pad state values
+ int _Lx, _Ly, _Rx, _Ry, _Tl, _Tr;
+ PadStateAdjustments(_Lx, _Ly, _Rx, _Ry, _Tl, _Tr);
+ // The Y-axis is inverted
+ _Ly = 0xff - _Ly;
+ _Ry = 0xff - _Ry;
+
+ /* This is if we are also using a real Nunchuck that we are sharing the calibration with. It's not
+ needed if we are using our default values. We adjust the values to the configured range, we even
+ allow the center to not be 0x80. */
+ if(g_nu.jx.max != 0xff || g_nu.jy.max != 0xff
+ || g_nu.jx.min != 0 || g_nu.jy.min != 0
+ || g_nu.jx.center != 0x80 || g_nu.jy.center != 0x80)
+ {
+ float Lx = (float)_Lx;
+ float Ly = (float)_Ly;
+ float Rx = (float)_Rx;
+ float Ry = (float)_Ry;
+ float Tl = (float)_Tl;
+ float Tr = (float)_Tr;
+
+ float XRangePos = (float) (g_nu.jx.max - g_nu.jx.center);
+ float XRangeNeg = (float) (g_nu.jx.center - g_nu.jx.min);
+ float YRangePos = (float) (g_nu.jy.max - g_nu.jy.center);
+ float YRangeNeg = (float) (g_nu.jy.center - g_nu.jy.min);
+ if (Lx > 0x80) Lx = Lx * (XRangePos / 128.0);
+ if (Lx < 0x80) Lx = Lx * (XRangeNeg / 128.0);
+ if (Lx == 0x80) Lx = (float)g_nu.jx.center;
+ if (Ly > 0x80) Ly = Ly * (YRangePos / 128.0);
+ if (Ly < 0x80) Ly = Ly * (YRangeNeg / 128.0);
+ if (Ly == 0x80) Lx = (float)g_nu.jy.center;
+ // Boundaries
+ _Lx = (int)Lx;
+ _Ly = (int)Ly;
+ _Rx = (int)Rx;
+ _Ry = (int)Ry;
+ if (_Lx > 0xff) _Lx = 0xff; if (_Lx < 0) _Lx = 0;
+ if (_Rx > 0xff) _Rx = 0xff; if (_Rx < 0) _Rx = 0;
+ if (_Ly > 0xff) _Ly = 0xff; if (_Ly < 0) _Ly = 0;
+ if (_Ry > 0xff) _Ry = 0xff; if (_Ry < 0) _Ry = 0;
+ }
+
+ if (g_Config.Nunchuck.Type == g_Config.Nunchuck.ANALOG1)
+ {
+ _ext.jx = _Lx;
+ _ext.jy = _Ly;
+ }
+ else // ANALOG2
+ {
+ _ext.jx = _Rx;
+ _ext.jy = _Ry;
+ }
+ }
+
+ if(IsKey(g_Nc.C))
+ _ext.bt = 0x01;
+ if(IsKey(g_Nc.Z))
+ _ext.bt = 0x02;
+ if(IsKey(g_Nc.C) && IsKey(g_Nc.Z))
+ _ext.bt = 0x00;
+
+ /* Here we encrypt the report */
+
+ // Create a temporary storage for the data
+ u8 Tmp[sizeof(_ext)];
+ // Clear the array by copying zeroes to it
+ memset(Tmp, 0, sizeof(_ext));
+ // Copy the data to it
+ memcpy(Tmp, &_ext, sizeof(_ext));
+ // Encrypt it
+ wiimote_encrypt(&g_ExtKey, Tmp, 0x00, sizeof(_ext));
+ // Write it back to the struct
+ memcpy(&_ext, Tmp, sizeof(_ext));
+}
+// =======================
+
+
+// ===================================================
+/* Generate the 6 byte extension report for the Classic Controller, encrypted.
+ The bytes are ... */
+// ----------------
+void FillReportClassicExtension(wm_classic_extension& _ext)
+{
+ /* These are the default neutral values for the analog triggers and sticks */
+ u8 Rx = g_cc.Rx.center, Ry = g_cc.Ry.center,
+ Lx = g_cc.Lx.center, Ly = g_cc.Ly.center,
+ lT = g_cc.Tl.neutral, rT = g_cc.Tl.neutral;
+
+ _ext.b1.padding = 0x01; // 0x01 means not pressed
+ _ext.b1.bRT = 0x01;
+ _ext.b1.bP = 0x01;
+ _ext.b1.bH = 0x01;
+ _ext.b1.bM = 0x01;
+ _ext.b1.bLT = 0x01;
+ _ext.b1.bdD = 0x01;
+ _ext.b1.bdR = 0x01;
+
+ _ext.b2.bdU = 0x01;
+ _ext.b2.bdL = 0x01;
+ _ext.b2.bZR = 0x01;
+ _ext.b2.bX = 0x01;
+ _ext.b2.bA = 0x01;
+ _ext.b2.bY = 0x01;
+ _ext.b2.bB = 0x01;
+ _ext.b2.bZL = 0x01;
+
+ // --------------------------------------
+ // Check that Dolphin is in focus
+ if (IsFocus())
+ {
+ // --------------------------------------
+ /* Left and right analog sticks and analog triggers
+
+ u8 Lx : 6; // byte 0
+ u8 Rx : 2;
+ u8 Ly : 6; // byte 1
+ u8 Rx2 : 2;
+ u8 Ry : 5; // byte 2
+ u8 lT : 2;
+ u8 Rx3 : 1;
+ u8 rT : 5; // byte 3
+ u8 lT2 : 3;
+
+ We use a 200 range (28 to 228) for the left analog stick and a 176 range
+ (40 to 216) for the right analog stick to match our calibration values
+ in classic_calibration
+ */
+
+ // Update the left analog stick
+ if (g_Config.ClassicController.LType == g_Config.ClassicController.KEYBOARD)
+ {
+ if(IsKey(g_Cc.Ll)) // Left analog left
+ Lx = g_cc.Lx.min;
+ if(IsKey(g_Cc.Lu)) // up
+ Ly = g_cc.Ly.max;
+ if(IsKey(g_Cc.Lr)) // right
+ Lx = g_cc.Lx.max;
+ if(IsKey(g_Cc.Ld)) // down
+ Ly = g_cc.Ly.min;
+
+ }
+ else
+ {
+ // Get adjusted pad state values
+ int _Lx, _Ly, _Rx, _Ry, _Tl, _Tr;
+ PadStateAdjustments(_Lx, _Ly, _Rx, _Ry, _Tl, _Tr);
+ // The Y-axis is inverted
+ _Ly = 0xff - _Ly;
+ _Ry = 0xff - _Ry;
+
+ /* This is if we are also using a real Classic Controller that we are sharing the calibration with.
+ It's not needed if we are using our default values. We adjust the values to the configured range.
+
+ Status: Not added, we are not currently sharing the calibration with the real Classic Controller
+ */
+
+ if (g_Config.ClassicController.LType == g_Config.ClassicController.ANALOG1)
+ {
+ Lx = _Lx;
+ Ly = _Ly;
+ }
+ else // ANALOG2
+ {
+ Lx = _Rx;
+ Ly = _Ry;
+ }
+ }
+
+ // Update the right analog stick
+ if (g_Config.ClassicController.RType == g_Config.ClassicController.KEYBOARD)
+ {
+ if(IsKey(g_Cc.Rl)) // Right analog left
+ Rx = g_cc.Rx.min;
+ if(IsKey(g_Cc.Ru)) // up
+ Ry = g_cc.Ry.max;
+ if(IsKey(g_Cc.Rr)) // right
+ Rx = g_cc.Rx.max;
+ if(IsKey(g_Cc.Rd)) // down
+ Ry = g_cc.Ry.min;
+ }
+ else
+ {
+ // Get adjusted pad state values
+ int _Lx, _Ly, _Rx, _Ry, _Tl, _Tr;
+ PadStateAdjustments(_Lx, _Ly, _Rx, _Ry, _Tl, _Tr);
+ // The Y-axis is inverted
+ _Ly = 0xff - _Ly;
+ _Ry = 0xff - _Ry;
+
+ /* This is if we are also using a real Classic Controller that we are sharing the calibration with.
+ It's not needed if we are using our default values. We adjust the values to the configured range.
+
+ Status: Not added, we are not currently sharing the calibration with the real Classic Controller
+ */
+
+ if (g_Config.ClassicController.RType == g_Config.ClassicController.ANALOG1)
+ {
+ Rx = _Lx;
+ Ry = _Ly;
+ }
+ else // ANALOG2
+ {
+ Rx = _Rx;
+ Ry = _Ry;
+ }
+ }
+
+ // Update the left and right analog triggers
+ if (g_Config.ClassicController.TType == g_Config.ClassicController.KEYBOARD)
+ {
+ if(IsKey(g_Cc.Tl)) // analog left trigger
+ { _ext.b1.bLT = 0x00; lT = 0x1f; }
+ if(IsKey(g_Cc.Tr)) // analog right trigger
+ { _ext.b1.bRT = 0x00; rT = 0x1f; }
+ }
+ else // g_Config.ClassicController.TRIGGER
+ {
+ // Get adjusted pad state values
+ int _Lx, _Ly, _Rx, _Ry, _Tl, _Tr;
+ PadStateAdjustments(_Lx, _Ly, _Rx, _Ry, _Tl, _Tr);
+
+ /* This is if we are also using a real Classic Controller that we are sharing the calibration with.
+ It's not needed if we are using our default values. We adjust the values to the configured range.
+
+ Status: Not added, we are not currently sharing the calibration with the real Classic Controller
+ */
+
+ // Check if the trigger is fully pressed, then update the digital trigger values to
+ if (_Tl == 0xff) _ext.b1.bLT = 0x00;
+ if (_Tr == 0xff) _ext.b1.bRT = 0x00;
+
+ // These can be copied directly, the bitshift further down fix this value to
+ lT = _Tl;
+ rT = _Tr;
+ }
+
+
+ // --------------
+
+ // --------------------------------------
+ /* D-Pad
+
+ u8 b1;
+ 0:
+ 6: bdD
+ 7: bdR
+
+ u8 b2;
+ 0: bdU
+ 1: bdL
+ */
+ if(IsKey(g_Cc.Dl)) _ext.b2.bdL = 0x00; // Digital left
+ if(IsKey(g_Cc.Du)) _ext.b2.bdU = 0x00; // Up
+ if(IsKey(g_Cc.Dr)) _ext.b1.bdR = 0x00; // Right
+ if(IsKey(g_Cc.Dd)) _ext.b1.bdD = 0x00; // Down
+ // --------------
+
+ // --------------------------------------
+ /* Buttons
+ u8 b1;
+ 0:
+ 6: -
+ 7: -
+
+ u8 b2;
+ 0: -
+ 1: -
+ 2: bZr
+ 3: bX
+ 4: bA
+ 5: bY
+ 6: bB
+ 7: bZl
+ */
+ if(IsKey(g_Cc.A))
+ _ext.b2.bA = 0x00;
+
+ if(IsKey(g_Cc.B))
+ _ext.b2.bB = 0x00;
+
+ if(IsKey(g_Cc.Y))
+ _ext.b2.bY = 0x00;
+
+ if(IsKey(g_Cc.X))
+ _ext.b2.bX = 0x00;
+
+ if(IsKey(g_Cc.P)) // O instead of P
+ _ext.b1.bP = 0x00;
+
+ if(IsKey(g_Cc.M)) // N instead of M
+ _ext.b1.bM = 0x00;
+
+ if(IsKey(g_Cc.H)) // Home button
+ _ext.b1.bH = 0x00;
+
+ if(IsKey(g_Cc.Zl)) // Digital left trigger
+ _ext.b2.bZL = 0x00;
+
+ if(IsKey(g_Cc.Zr)) // Digital right trigger
+ _ext.b2.bZR = 0x00;
+
+ // All buttons pressed
+ //if(GetAsyncKeyState('C') && GetAsyncKeyState('Z'))
+ // { _ext.b2.bA = 0x01; _ext.b2.bB = 0x01; }
+ // --------------
+ }
+ // --------------------------------------
+
+
+ // --------------------------------------
+ // Convert data for reporting
+ // --------------
+ _ext.Lx = (Lx >> 2);
+ _ext.Ly = (Ly >> 2);
+ // 5 bit to 1 bit
+ _ext.Rx = (Rx >> 3) & 0x01;
+ // 5 bit to the next 2 bit
+ _ext.Rx2 = ((Rx >> 3) >> 1) & 0x03;
+ // 5 bit to the next 2 bit
+ _ext.Rx3 = ((Rx >> 3) >> 3) & 0x03;
+ _ext.Ry = (Ry >> 3);
+
+ // 5 bit to 3 bit
+ _ext.lT = (lT >> 3) & 0x07;
+ // 5 bit to the highest two bits
+ _ext.lT2 = (lT >> 3) >> 3;
+ _ext.rT = (rT >> 3);
+ // --------------
+
+
+ /* Here we encrypt the report */
+
+ // Create a temporary storage for the data
+ u8 Tmp[sizeof(_ext)];
+ // Clear the array by copying zeroes to it
+ memset(Tmp, 0, sizeof(_ext));
+ // Copy the data to it
+ memcpy(Tmp, &_ext, sizeof(_ext));
+ // Encrypt it
+ wiimote_encrypt(&g_ExtKey, Tmp, 0x00, sizeof(_ext));
+ // Write it back to the struct
+ memcpy(&_ext, Tmp, sizeof(_ext));
+}
+// =======================
+
+
+} // end of namespace
diff --git a/Source/Plugins/Plugin_Wiimote-testing/Src/Logging.cpp b/Source/Plugins/Plugin_Wiimote-testing/Src/Logging.cpp
new file mode 100644
index 0000000000..df398aa805
--- /dev/null
+++ b/Source/Plugins/Plugin_Wiimote-testing/Src/Logging.cpp
@@ -0,0 +1,119 @@
+// Copyright (C) 2003-2008 Dolphin Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official SVN repository and contact information can be found at
+// http://code.google.com/p/dolphin-emu/
+
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Includes
+// -------------
+#include
+#include
+#ifdef _WIN32
+ #include
+#endif
+
+#include "StringUtil.h"
+
+#define HAVE_WX 1
+#if defined(HAVE_WX) && HAVE_WX // wxWidgets
+ #include // for the timestamps
+#endif
+///////////////////////////
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Settings
+// -------------
+
+// On and off
+bool g_consoleEnable = true;
+bool gSaveFile = true;
+#define DEBUG_WIIMOTE // On or off
+const int nFiles = 1;
+
+// Create handles
+#ifdef DEBUG_WIIMOTE
+ FILE* __fStdOut[nFiles];
+#endif
+#ifdef _WIN32
+ HANDLE __hStdOut = NULL;
+#endif
+
+//////////////////////////////
+
+
+// =======================================================================================
+/* Get Timestamp */
+// -------------
+std::string Tm(bool Ms)
+{
+ #if defined(HAVE_WX) && HAVE_WX
+ std::string Tmp;
+ if(Ms)
+ {
+ wxDateTime datetime = wxDateTime::UNow(); // Get timestamp
+ Tmp = StringFromFormat("%02i:%02i:%03i",
+ datetime.GetMinute(), datetime.GetSecond(), datetime.GetMillisecond());
+ }
+ else
+ {
+ wxDateTime datetime = wxDateTime::Now(); // Get timestamp
+ Tmp = StringFromFormat("%02i:%02i",
+ datetime.GetMinute(), datetime.GetSecond());
+ }
+ return Tmp;
+ #else
+ std::string Tmp = "";
+ return Tmp;
+ #endif
+}
+// ===========================
+
+
+// ---------------------------------------------------------------------------------------
+// File printf function
+// ---------------
+int PrintFile(int a, char *fmt, ...)
+{
+#if defined(DEBUG_WIIMOTE) && defined(_WIN32)
+ if(gSaveFile)
+ {
+ char s[500]; // WARNING: mind this value
+ va_list argptr;
+ int cnt;
+
+ va_start(argptr, fmt);
+ cnt = vsnprintf(s, 500, fmt, argptr); // remember to update this value to
+ va_end(argptr);
+
+ // ---------------------------------------------------------------------------------------
+ if(__fStdOut[a]) // TODO: make this work, we have to set all default values to NULL
+ //to make it work
+ fprintf(__fStdOut[a], s);
+ fflush(__fStdOut[0]); // Write file now, don't wait
+ // -------------
+
+ return(cnt);
+ }
+ else
+ {
+ return 0;
+ }
+#else
+ return 0;
+#endif
+}
diff --git a/Source/Plugins/Plugin_Wiimote-testing/Src/Logging.h b/Source/Plugins/Plugin_Wiimote-testing/Src/Logging.h
new file mode 100644
index 0000000000..965aa9def1
--- /dev/null
+++ b/Source/Plugins/Plugin_Wiimote-testing/Src/Logging.h
@@ -0,0 +1,40 @@
+// Copyright (C) 2003-2008 Dolphin Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official SVN repository and contact information can be found at
+// http://code.google.com/p/dolphin-emu/
+
+#ifndef WIIMOTE_CONSOLE_H
+#define WIIMOTE_CONSOLE_H
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Includes
+// ŻŻŻŻŻŻŻŻŻŻŻŻŻ
+#include
+//////////////////////////////
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Declarations
+// ŻŻŻŻŻŻŻŻŻŻŻŻŻ
+std::string Tm(bool Ms = false);
+int PrintFile(int a, const char *fmt, ...);
+void ClearScreen();
+
+#ifdef _WIN32
+ HWND GetConsoleHwnd(void);
+#endif
+///////////////////////////////
+
+#endif // WIIMOTE_CONSOLE_H
+
diff --git a/Source/Plugins/Plugin_Wiimote-testing/Src/ReadWiimote.cpp b/Source/Plugins/Plugin_Wiimote-testing/Src/ReadWiimote.cpp
new file mode 100644
index 0000000000..c0f113dce5
--- /dev/null
+++ b/Source/Plugins/Plugin_Wiimote-testing/Src/ReadWiimote.cpp
@@ -0,0 +1,387 @@
+// Copyright (C) 2003-2008 Dolphin Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official SVN repository and contact information can be found at
+// http://code.google.com/p/dolphin-emu/
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Includes
+// ŻŻŻŻŻŻŻŻŻŻŻŻŻ
+#include // System
+
+#include "wiiuse.h" // Externals
+
+#include "StringUtil.h"
+#include "Timer.h"
+#include "pluginspecs_wiimote.h"
+
+#include "wiimote_real.h" // Local
+#include "wiimote_hid.h"
+#include "EmuDefinitions.h"
+#include "EmuMain.h"
+#include "main.h"
+#if defined(HAVE_WX) && HAVE_WX
+ #include "ConfigDlg.h"
+#endif
+#include "Config.h"
+////////////////////////////////////////
+
+namespace WiiMoteReal
+{
+int GetReportSize(struct wiimote_t* wm)
+{
+ // The report size is 0x33 = 18, 0x37 = 22 withouth the leading (a1) byte
+ if(WIIUSE_USING_EXP(wm)) return 22; else return 18;
+}
+
+void handle_ctrl_status(struct wiimote_t* wm)
+{
+ INFO_LOG(CONSOLE, "\n\n--- CONTROLLER STATUS [wiimote id %i] ---\n", wm->unid);
+
+ INFO_LOG(CONSOLE, "attachment: %i\n", wm->exp.type);
+ INFO_LOG(CONSOLE, "speaker: %i\n", WIIUSE_USING_SPEAKER(wm));
+ INFO_LOG(CONSOLE, "ir: %i\n", WIIUSE_USING_IR(wm));
+ INFO_LOG(CONSOLE, "leds: %i %i %i %i\n", WIIUSE_IS_LED_SET(wm, 1), WIIUSE_IS_LED_SET(wm, 2), WIIUSE_IS_LED_SET(wm, 3), WIIUSE_IS_LED_SET(wm, 4));
+ INFO_LOG(CONSOLE, "battery: %f %%\n", wm->battery_level);
+}
+
+bool IRDataOK(struct wiimote_t* wm)
+{
+ //INFO_LOG(CONSOLE, "IRDataOK: ");
+ // The report size is 0x33 = 18, 0x37 = 22 withouth the leading (a1) byte
+ int ReportSize = GetReportSize(wm);
+ for(int i = 0; i < ReportSize; i++)
+ {
+ //INFO_LOG(CONSOLE, "%02x ", wm->event_buf[i]);
+ if (wm->event_buf[i] > 0)
+ {
+ //INFO_LOG(CONSOLE, "\n");
+ return true;
+ }
+ }
+ return false;
+}
+
+void handle_event(struct wiimote_t* wm)
+{
+ //INFO_LOG(CONSOLE, "\n\n--- EVENT [id %i] ---\n", wm->unid);
+
+ // if a button is pressed, report it
+ if (IS_PRESSED(wm, WIIMOTE_BUTTON_A)) INFO_LOG(CONSOLE, "A pressed\n");
+ if (IS_PRESSED(wm, WIIMOTE_BUTTON_B)) INFO_LOG(CONSOLE, "B pressed\n");
+ if (IS_PRESSED(wm, WIIMOTE_BUTTON_UP)) INFO_LOG(CONSOLE, "UP pressed\n");
+ if (IS_PRESSED(wm, WIIMOTE_BUTTON_DOWN)) INFO_LOG(CONSOLE, "DOWN pressed\n");
+ if (IS_PRESSED(wm, WIIMOTE_BUTTON_LEFT)) INFO_LOG(CONSOLE, "LEFT pressed\n");
+ if (IS_PRESSED(wm, WIIMOTE_BUTTON_RIGHT)) INFO_LOG(CONSOLE, "RIGHT pressed\n");
+ if (IS_PRESSED(wm, WIIMOTE_BUTTON_MINUS)) INFO_LOG(CONSOLE, "MINUS pressed\n");
+ if (IS_PRESSED(wm, WIIMOTE_BUTTON_PLUS)) INFO_LOG(CONSOLE, "PLUS pressed\n");
+ if (IS_PRESSED(wm, WIIMOTE_BUTTON_ONE)) INFO_LOG(CONSOLE, "ONE pressed\n");
+ //if (IS_PRESSED(wm, WIIMOTE_BUTTON_ONE)) g_Run = false;
+ if (IS_PRESSED(wm, WIIMOTE_BUTTON_TWO)) INFO_LOG(CONSOLE, "TWO pressed\n");
+ if (IS_PRESSED(wm, WIIMOTE_BUTTON_HOME)) INFO_LOG(CONSOLE, "HOME pressed\n");
+
+
+ // Pressing minus will tell the wiimote we are no longer interested in movement.
+ // This is useful because it saves battery power.
+ if (IS_JUST_PRESSED(wm, WIIMOTE_BUTTON_MINUS))
+ {
+ wiiuse_motion_sensing(wm, 0);
+ wiiuse_set_ir(wm, 0);
+ g_MotionSensing = false;
+ }
+ // Turn aceelerometer and IR reporting on, there is some kind of bug that prevents us from turing these on
+ // directly after each other, so we have to wait for another wiiuse_poll() this way
+ if (IS_JUST_PRESSED(wm, WIIMOTE_BUTTON_PLUS))
+ {
+ wiiuse_motion_sensing(wm, 1);
+ g_MotionSensing = true;
+ }
+ // Turn IR reporting on
+ if (g_MotionSensing && !WIIUSE_USING_IR(wm))
+ wiiuse_set_ir(wm, 1);
+
+ // Print battery status
+#if defined(HAVE_WX) && HAVE_WX
+ if(frame && g_Config.bUpdateRealWiimote)
+ frame->m_GaugeBattery->SetValue((int)floor((wm->battery_level * 100) + 0.5));
+#endif
+ // Create shortcut to the nunchuck
+ struct nunchuk_t* nc = NULL;
+ if (wm->exp.type == EXP_NUNCHUK)
+ nc = (nunchuk_t*)&wm->exp.nunchuk;
+
+ // If the accelerometer is turned on then print angles
+ if (WIIUSE_USING_ACC(wm) && WIIUSE_USING_IR(wm))
+ {
+ std::string Tmp;
+ Tmp += StringFromFormat("Roll: %2.1f ", wm->orient.roll);
+ Tmp += StringFromFormat("Pitch: %2.1f ", wm->orient.pitch);
+ Tmp += StringFromFormat("Battery: %1.2f\n", wm->battery_level);
+ Tmp += StringFromFormat("G-Force x, y, z: %1.2f %1.2f %1.2f\n", wm->gforce.x, wm->gforce.y, wm->gforce.z);
+ Tmp += StringFromFormat("Accel x, y, z: %03i %03i %03i\n", wm->accel.x, wm->accel.y, wm->accel.z);
+
+ // The report size is 0x33 = 18, 0x37 = 22
+ int ReportSize; if(WIIUSE_USING_EXP(wm)) ReportSize = 22; else ReportSize = 18;
+
+ // wm->event_buf is cleared at the end of all wiiuse_poll(), so wm->event_buf will always be zero
+ // after that. To get the raw IR data we need to read the wiimote again. This seems to work most of the time,
+ // it seems to fails with a regular interval about each tenth read.
+ if(wiiuse_io_read(wm))
+ {
+ // Check that it's not zero
+ if (IRDataOK(wm)) memcpy(g_EventBuffer, wm->event_buf, ReportSize);
+ }
+
+ // Go through each of the 4 possible IR sources
+ for (int i = 0; i < 4; ++i)
+ {
+ // Check if the source is visible
+ if (wm->ir.dot[i].visible)
+ Tmp += StringFromFormat("IR source %i: (%u, %u)\n", i, wm->ir.dot[i].x, wm->ir.dot[i].y);
+ }
+
+ Tmp += "\n";
+ Tmp += StringFromFormat("IR cursor: (%u, %u)\n", wm->ir.x, wm->ir.y);
+ Tmp += StringFromFormat("IR z distance: %f\n", wm->ir.z);
+
+ if(wm->exp.type == EXP_NUNCHUK)
+ {
+ Tmp += "\n";
+ Tmp += StringFromFormat("Nunchuck accel x, y, z: %03i %03i %03i\n", nc->accel.x, nc->accel.y, nc->accel.z);
+ }
+
+ //Tmp += "\n";
+ //std::string TmpData = ArrayToString(g_EventBuffer, ReportSize, 0, 30);
+ //Tmp += "Data: " + TmpData;
+
+ //Console::ClearScreen();
+ //INFO_LOG(CONSOLE, "%s\n\n", Tmp.c_str());
+
+#if defined(HAVE_WX) && HAVE_WX
+ if(frame)
+ {
+ // Produce adjusted accelerometer values
+ float _Gx = (float)(wm->accel.x - wm->accel_calib.cal_zero.x) / (float)wm->accel_calib.cal_g.x;
+ float _Gy = (float)(wm->accel.y - wm->accel_calib.cal_zero.y) / (float)wm->accel_calib.cal_g.y;
+ float _Gz = (float)(wm->accel.z - wm->accel_calib.cal_zero.z) / (float)wm->accel_calib.cal_g.z;
+
+ // Conver the data to integers
+ int Gx = (int)(_Gx * 100);
+ int Gy = (int)(_Gy * 100);
+ int Gz = (int)(_Gz * 100);
+
+ // And for the Nunchuck
+ u8 AccelNX = 0, AccelNY = 0, AccelNZ = 0;
+ if(wm->exp.type == EXP_NUNCHUK)
+ {
+ if((nc->accel.x + g_Config.iAccNunNeutralX) <= 255) AccelNX = nc->accel.x + g_Config.iAccNunNeutralX;
+ if((nc->accel.y + g_Config.iAccNunNeutralY) <= 255) AccelNY = nc->accel.y + g_Config.iAccNunNeutralY;
+ if((nc->accel.z + g_Config.iAccNunNeutralZ) <= 255) AccelNZ = nc->accel.z + g_Config.iAccNunNeutralZ;
+ }
+
+ if(g_Config.bUpdateRealWiimote)
+ {
+ // Update gauges
+ frame->m_GaugeRoll[0]->SetValue(wm->orient.roll + 180);
+ frame->m_GaugeRoll[1]->SetValue(wm->orient.pitch + 180);
+
+ // Show g. forces between -3 and 3
+ frame->m_GaugeGForce[0]->SetValue((int)floor((wm->gforce.x * 100) + 300.5));
+ frame->m_GaugeGForce[1]->SetValue((int)floor((wm->gforce.y * 100) + 300.5));
+ frame->m_GaugeGForce[2]->SetValue((int)floor((wm->gforce.z * 100) + 300.5));
+
+ frame->m_GaugeAccel[0]->SetValue(wm->accel.x);
+ frame->m_GaugeAccel[1]->SetValue(wm->accel.y);
+ frame->m_GaugeAccel[2]->SetValue(wm->accel.z);
+
+ frame->m_TextIR->SetLabel(wxString::Format(
+ wxT("Cursor: %03u %03u\nDistance:%4.0f"), wm->ir.x, wm->ir.y, wm->ir.z));
+
+ //frame->m_TextAccNeutralCurrent->SetLabel(wxString::Format(
+ // wxT("Current: %03u %03u %03u"), Gx, Gy, Gz));
+
+ if(frame->m_bRecording)
+ INFO_LOG(CONSOLE, "Wiiuse Recorded accel x, y, z: %03i %03i %03i\n", Gx, Gy, Gz);
+ //INFO_LOG(CONSOLE, "Wiiuse Recorded accel x, y, z: %02x %02x %02x\n", Gx, Gy, Gz);
+ }
+
+ // Send the data to be saved
+ //const u8* data = (const u8*)wm->event_buf;
+ frame->DoRecordMovement(Gx, Gy, Gz, (g_EventBuffer + 6),
+ (WIIUSE_USING_EXP(wm) ? 10 : 12));
+
+ // Turn recording on and off
+ if (IS_PRESSED(wm, WIIMOTE_BUTTON_A)) frame->DoRecordA(true);
+ else frame->DoRecordA(false);
+
+ // ------------------------------------
+ // Show roll and pitch in the status box
+ // --------------
+ /*
+ if(!g_DebugData)
+ {
+// Console::ClearScreen();
+ INFO_LOG(CONSOLE, "Roll:%03i Pitch:%03i\n", (int)wm->orient.roll, (int)wm->orient.pitch);
+ }
+ // Convert Roll and Pitch from 180 to 0x8000
+ int Roll = (int)wm->orient.roll * (0x8000 / 180);
+ int Pitch = (int)wm->orient.pitch * (0x8000 / 180);
+ // Convert it to the box
+ frame->Convert2Box(Roll);
+ frame->Convert2Box(Pitch);
+ // Show roll and pitch in the axis boxes
+ frame->m_bmpDotRightOut[0]->SetPosition(wxPoint(Roll, Pitch));*/
+ // ---------------------
+ }
+#endif
+ }
+ // Otherwise remove the values
+ else
+ {
+#if defined(HAVE_WX) && HAVE_WX
+ if (frame)
+ {
+ frame->m_GaugeRoll[0]->SetValue(0);
+ frame->m_GaugeRoll[1]->SetValue(0);
+
+ frame->m_GaugeGForce[0]->SetValue(0);
+ frame->m_GaugeGForce[1]->SetValue(0);
+ frame->m_GaugeGForce[2]->SetValue(0);
+
+ frame->m_GaugeAccel[0]->SetValue(0);
+ frame->m_GaugeAccel[1]->SetValue(0);
+ frame->m_GaugeAccel[2]->SetValue(0);
+
+ frame->m_TextIR->SetLabel(wxT("Cursor:\nDistance:"));
+ }
+#endif
+ }
+}
+
+void ReadWiimote()
+{
+ /* I place this outside wiiuse_poll() to produce a continous recording regardless of the status
+ change of the Wiimote, wiiuse_poll() is only true if the status has changed. However, this the
+ timing functions for recording playback that checks the time of the recording this should not
+ be needed. But I still use it becase it seemed like state_changed() or the threshold values or
+ something else might fail so that only huge status changed were reported. */
+ for (int i = 0; i < g_NumberOfWiiMotes; i++)
+ {
+ handle_event(g_WiiMotesFromWiiUse[i]);
+ }
+
+ // Declaration
+ std::string Temp;
+
+ /* Timeout for data reading. This is used in Initialize() to read the Eeprom, if we have not gotten
+ what we wanted in the WIIUSE_READ_DATA case we stop this loop and enable the regular
+ wiiuse_io_read() and wiiuse_io_write() loop again. */
+ if (g_RunTemporary)
+ {
+ // The SecondsToWait holds if the update rate of wiiuse_poll() is kept at the default value of 10 ms
+ static const int SecondsToWait = 2;
+ g_RunTemporaryCountdown++;
+ if(g_RunTemporaryCountdown > (SecondsToWait * 100))
+ {
+ g_RunTemporaryCountdown = 0;
+ g_RunTemporary = false;
+ }
+ }
+
+ // Read formatted Wiimote data
+ if (wiiuse_poll(g_WiiMotesFromWiiUse, MAX_WIIMOTES))
+ {
+ /*
+ * This happens if something happened on any wiimote.
+ * So go through each one and check if anything happened.
+ */
+ int i = 0;
+ for (; i < MAX_WIIMOTES; ++i)
+ {
+ switch (g_WiiMotesFromWiiUse[i]->event)
+ {
+ case WIIUSE_EVENT:
+ /* a generic event occured */
+ //handle_event(g_WiiMotesFromWiiUse[i]);
+ break;
+
+ case WIIUSE_STATUS:
+ /* a status event occured */
+ //handle_ctrl_status(g_WiiMotesFromWiiUse[i]);
+ break;
+
+ case WIIUSE_DISCONNECT:
+ case WIIUSE_UNEXPECTED_DISCONNECT:
+ /* the wiimote disconnected */
+ //handle_disconnect(wiimotes[i]);
+ break;
+
+ case WIIUSE_READ_DATA:
+ /*
+ * Data we requested to read was returned.
+ * Take a look at wiimotes[i]->read_req
+ * for the data.
+ */
+ if(g_WiiMotesFromWiiUse[i]->read_req->size == sizeof(WiiMoteEmu::EepromData_0)
+ && g_WiiMotesFromWiiUse[i]->read_req->addr == 0)
+ {
+ Temp = ArrayToString(g_WiiMotesFromWiiUse[i]->read_req->buf, sizeof(WiiMoteEmu::EepromData_0), 0, 30);
+ memcpy(WiiMoteEmu::g_Eeprom, g_WiiMotesFromWiiUse[i]->read_req->buf, sizeof(WiiMoteEmu::EepromData_0));
+ INFO_LOG(CONSOLE, "EEPROM: %s\n", Temp.c_str());
+ WiiMoteEmu::UpdateEeprom();
+ g_RunTemporary = false;
+ }
+ break;
+
+ case WIIUSE_NUNCHUK_INSERTED:
+ /*
+ * a nunchuk was inserted
+ * This is a good place to set any nunchuk specific
+ * threshold values. By default they are the same
+ * as the wiimote.
+ */
+ //wiiuse_set_nunchuk_orient_threshold((struct nunchuk_t*)&wiimotes[i]->exp.nunchuk, 90.0f);
+ //wiiuse_set_nunchuk_accel_threshold((struct nunchuk_t*)&wiimotes[i]->exp.nunchuk, 100);
+ INFO_LOG(CONSOLE, "Nunchuk inserted.\n");
+ break;
+
+ case WIIUSE_CLASSIC_CTRL_INSERTED:
+ INFO_LOG(CONSOLE, "Classic controller inserted.\n");
+ break;
+
+ case WIIUSE_GUITAR_HERO_3_CTRL_INSERTED:
+ // some expansion was inserted
+ //handle_ctrl_status(wiimotes[i]);
+ INFO_LOG(CONSOLE, "Guitar Hero 3 controller inserted.\n");
+ break;
+
+ case WIIUSE_NUNCHUK_REMOVED:
+ case WIIUSE_CLASSIC_CTRL_REMOVED:
+ case WIIUSE_GUITAR_HERO_3_CTRL_REMOVED:
+ // some expansion was removed
+ //handle_ctrl_status(wiimotes[i]);
+ INFO_LOG(CONSOLE, "An expansion was removed.\n");
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+}
+
+
+}; // end of namespace
+
diff --git a/Source/Plugins/Plugin_Wiimote-testing/Src/SConscript b/Source/Plugins/Plugin_Wiimote-testing/Src/SConscript
new file mode 100644
index 0000000000..a596bbe597
--- /dev/null
+++ b/Source/Plugins/Plugin_Wiimote-testing/Src/SConscript
@@ -0,0 +1,53 @@
+# -*- python -*-
+
+Import('env')
+import sys
+
+wmenv = env.Clone()
+name = "Plugin_Wiimote"
+
+files = [
+ "Config.cpp",
+ "DataReports.cpp",
+ "EmuDefinitions.cpp",
+ "EmuDynamics.cpp",
+ "EmuMain.cpp",
+ "EmuPad.cpp",
+ "EmuSubroutines.cpp",
+ "Encryption.cpp",
+ "main.cpp",
+ ]
+if wmenv['HAVE_WX']:
+ files += [
+ "ConfigDlg.cpp",
+ "ConfigGamepad.cpp",
+ "ConfigRecording.cpp",
+ "Logging.cpp",
+ "FillReport.cpp",
+ ]
+
+libs = [ 'common', 'inputcommon' ]
+
+
+cxxflags = [ '-fPIC' ]
+
+if wmenv['HAVE_WIIUSE']:
+ libs += [ 'wiiuse' ]
+ files += [ "wiimote_real.cpp" ]
+ files += [ "ReadWiimote.cpp" ]
+ cxxflags += ['-DHAVE_WIIUSE']
+
+if sys.platform == 'darwin':
+ wmenv.Append(
+ CXXFLAGS = cxxflags,
+ LINKFLAGS = ['-framework' ,'IOBluetooth'],
+ LIBS = libs,
+ )
+else:
+ wmenv.Append(
+ CXXFLAGS = cxxflags,
+ LIBS = libs,
+ )
+
+
+wmenv.SharedLibrary(env['plugin_dir']+name, files)
diff --git a/Source/Plugins/Plugin_Wiimote-testing/Src/main.cpp b/Source/Plugins/Plugin_Wiimote-testing/Src/main.cpp
new file mode 100644
index 0000000000..dfd6724d0c
--- /dev/null
+++ b/Source/Plugins/Plugin_Wiimote-testing/Src/main.cpp
@@ -0,0 +1,1103 @@
+// Copyright (C) 2003-2008 Dolphin Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official SVN repository and contact information can be found at
+// http://code.google.com/p/dolphin-emu/
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Current issues
+/* ŻŻŻŻŻŻŻŻŻŻŻŻŻ
+
+The real Wiimote fails to answer the core correctly sometmes. Leading to an unwanted disconnection. And
+there is currenty no functions to reconnect with the game. There are two ways to solve this:
+ 1. Make a reconnect function in the IOS emulation
+ 2. Detect failed answers in this plugin and solve it by replacing them with emulated answers.
+
+The first solution seems easier, if I knew a little better how the /dev/usb/oh1 and Wiimote functions
+worked.
+
+/////////////////////////////////////////////*/
+
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Includes
+// ŻŻŻŻŻŻŻŻŻŻŻŻŻ
+#include "Common.h" // Common
+#include "StringUtil.h"
+#include "Timer.h"
+
+#define EXCLUDEMAIN_H // Avoid certain declarations in main.h
+#include "EmuDefinitions.h" // Local
+#include "wiimote_hid.h"
+#include "main.h"
+#include "Logging.h"
+#if defined(HAVE_WX) && HAVE_WX
+ #include "ConfigDlg.h"
+#endif
+#include "Config.h"
+#include "pluginspecs_wiimote.h"
+#include "EmuMain.h"
+#if HAVE_WIIUSE
+ #include "wiimote_real.h"
+#endif
+///////////////////////////////////
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Declarations and definitions
+// ŻŻŻŻŻŻŻŻŻŻŻŻŻ
+SWiimoteInitialize g_WiimoteInitialize;
+PLUGIN_GLOBALS* globals = NULL;
+
+// General
+bool g_EmulatorRunning = false;
+u32 g_ISOId = 0;
+bool g_FrameOpen = false;
+bool g_RealWiiMotePresent = false;
+bool g_RealWiiMoteInitialized = false;
+bool g_EmulatedWiiMoteInitialized = false;
+bool g_WiimoteUnexpectedDisconnect = false;
+
+// Settings
+accel_cal g_wm;
+nu_cal g_nu;
+cc_cal g_cc;
+
+// Debugging
+bool g_DebugAccelerometer = false;
+bool g_DebugData = false;
+bool g_DebugComm = true;
+bool g_DebugSoundData = true;
+bool g_DebugCustom = false;
+
+// Update speed
+int g_UpdateCounter = 0;
+double g_UpdateTime = 0;
+int g_UpdateRate = 0;
+int g_UpdateWriteScreen = 0;
+std::vector g_UpdateTimeList (5, 0);
+
+// Movement recording
+std::vector VRecording(RECORDING_ROWS);
+
+// DLL instance
+HINSTANCE g_hInstance;
+
+#ifdef _WIN32
+HWND g_ParentHWND = NULL;
+#endif
+
+#if defined(HAVE_WX) && HAVE_WX
+ wxWindow win;
+ ConfigDialog *frame = NULL;
+
+ class wxDLLApp : public wxApp
+ {
+ bool OnInit()
+ {
+ return true;
+ }
+ };
+ IMPLEMENT_APP_NO_MAIN(wxDLLApp)
+ WXDLLIMPEXP_BASE void wxSetInstance(HINSTANCE hInst);
+#endif
+////////////////////////////////////
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Main function and WxWidgets initialization
+// ŻŻŻŻŻŻŻŻŻŻŻŻŻ
+#ifdef _WIN32
+BOOL APIENTRY DllMain(HINSTANCE hinstDLL, // DLL module handle
+ DWORD dwReason, // reason called
+ LPVOID lpvReserved) // reserved
+{
+ switch (dwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ { //use wxInitialize() if you don't want GUI instead of the following 12 lines
+ wxSetInstance((HINSTANCE)hinstDLL);
+ int argc = 0;
+ char **argv = NULL;
+ wxEntryStart(argc, argv);
+ if (!wxTheApp || !wxTheApp->CallOnInit())
+ return FALSE;
+ }
+ break;
+
+ case DLL_PROCESS_DETACH:
+ wxEntryCleanup(); //use wxUninitialize() if you don't want GUI
+ break;
+ default:
+ break;
+ }
+
+ g_hInstance = hinstDLL;
+ return TRUE;
+}
+#endif
+/////////////////////////////////////
+
+
+//******************************************************************************
+// Exports
+//******************************************************************************
+extern "C" void GetDllInfo (PLUGIN_INFO* _PluginInfo)
+{
+ _PluginInfo->Version = 0x0100;
+ _PluginInfo->Type = PLUGIN_TYPE_WIIMOTE;
+ #ifdef DEBUGFAST
+ sprintf(_PluginInfo->Name, "Dolphin Wiimote Plugin (DebugFast)");
+ #else
+ #ifndef _DEBUG
+ sprintf(_PluginInfo->Name, "Dolphin Wiimote Plugin");
+ #else
+ sprintf(_PluginInfo->Name, "Dolphin Wiimote Plugin (Debug)");
+ #endif
+ #endif
+}
+
+void SetDllGlobals(PLUGIN_GLOBALS* _pPluginGlobals)
+{
+ globals = _pPluginGlobals;
+ LogManager::SetInstance((LogManager *)globals->logManager);
+}
+
+void DllDebugger(HWND _hParent, bool Show) {}
+
+void DllConfig(HWND _hParent)
+{
+#if defined(HAVE_WX) && HAVE_WX
+
+ #ifdef _WIN32
+ win.SetHWND(_hParent);
+ #endif
+
+ //Console::Open();
+ DoInitialize();
+
+ frame = new ConfigDialog(&win);
+ g_FrameOpen = true;
+ /* We don't need to use ShowModal() anymore becaue FreeLibrary() is not called after this function
+ anymore */
+ frame->Show();
+
+ #ifdef _WIN32
+ win.SetHWND(0);
+ #endif
+
+#endif
+}
+
+extern "C" void Initialize(void *init)
+{
+ // Declarations
+ SWiimoteInitialize _WiimoteInitialize = *(SWiimoteInitialize *)init;
+ g_WiimoteInitialize = _WiimoteInitialize;
+
+ #ifdef _WIN32
+ g_ParentHWND = GetParent(g_WiimoteInitialize.hWnd);
+ #endif
+
+ g_EmulatorRunning = true;
+
+ // Update the GUI if the configuration window is already open
+ #if defined(HAVE_WX) && HAVE_WX
+ if (g_FrameOpen)
+ {
+ // Save the settings
+ g_Config.Save();
+ // Save the ISO Id
+ g_ISOId = g_WiimoteInitialize.ISOId;
+ // Load the settings
+ g_Config.Load();
+ if(frame) frame->UpdateGUI();
+ }
+ #endif
+
+ // Save the ISO Id, again if we had a window open
+ g_ISOId = g_WiimoteInitialize.ISOId;
+
+ DoInitialize();
+
+ INFO_LOG(CONSOLE, "ISOId: %08x %s\n", g_WiimoteInitialize.ISOId, Hex2Ascii(g_WiimoteInitialize.ISOId).c_str());
+}
+
+// If a game is not running this is called by the Configuration window when it's closed
+extern "C" void Shutdown(void)
+{
+ // Not running
+ g_EmulatorRunning = false;
+
+ // Reset the game ID in all cases
+ g_ISOId = 0;
+
+ // We will only shutdown when both a game and the frame is closed
+ if (g_FrameOpen)
+ {
+ #if defined(HAVE_WX) && HAVE_WX
+ if(frame) frame->UpdateGUI();
+ #endif
+
+ // Reset the variables
+ WiiMoteEmu::ResetVariables();
+
+ /* Don't shut down the wiimote when we still have the config window open, we may still want
+ want to use the Wiimote in the config window. */
+ return;
+ }
+
+#if HAVE_WIIUSE
+ if (g_RealWiiMoteInitialized) WiiMoteReal::Shutdown();
+#endif
+ WiiMoteEmu::Shutdown();
+
+ // Console::Close();
+}
+
+
+extern "C" void DoState(unsigned char **ptr, int mode)
+{
+#if HAVE_WIIUSE
+ WiiMoteReal::DoState(ptr, mode);
+#endif
+ WiiMoteEmu::DoState(ptr, mode);
+}
+
+
+// ===================================================
+/* This function produce Wiimote Input (reports from the Wiimote) in response
+ to Output from the Wii. It's called from WII_IPC_HLE_WiiMote.cpp.
+
+ Switch between real and emulated wiimote: We send all this Input to WiiMoteEmu::InterruptChannel()
+ so that it knows the channel ID and the data reporting mode at all times.
+ */
+// ----------------
+extern "C" void Wiimote_InterruptChannel(u16 _channelID, const void* _pData, u32 _Size)
+{
+ DEBUG_LOG(WII_IPC_WIIMOTE, "=============================================================");
+ const u8* data = (const u8*)_pData;
+
+ // Debugging
+ {
+ DEBUG_LOG(WII_IPC_WIIMOTE, "Wiimote_Input");
+ DEBUG_LOG(WII_IPC_WIIMOTE, " Channel ID: %04x", _channelID);
+ std::string Temp = ArrayToString(data, _Size);
+ DEBUG_LOG(WII_IPC_WIIMOTE, " Data: %s", Temp.c_str());
+ }
+
+ // Decice where to send the message
+ //if (!g_RealWiiMotePresent)
+ WiiMoteEmu::InterruptChannel(_channelID, _pData, _Size);
+#if HAVE_WIIUSE
+ if (g_RealWiiMotePresent)
+ WiiMoteReal::InterruptChannel(_channelID, _pData, _Size);
+#endif
+
+ DEBUG_LOG(WII_IPC_WIIMOTE, "=============================================================");
+}
+// ==============================
+
+
+// ===================================================
+/* Function: Used for the initial Bluetooth HID handshake. */
+// ----------------
+extern "C" void Wiimote_ControlChannel(u16 _channelID, const void* _pData, u32 _Size)
+{
+ DEBUG_LOG(WII_IPC_WIIMOTE, "=============================================================");
+ const u8* data = (const u8*)_pData;
+
+ // Check for custom communication
+ if(_channelID == 99 && data[0] == WIIMOTE_RECONNECT)
+ {
+ INFO_LOG(CONSOLE, "\n\nWiimote Disconnected\n\n");
+ g_EmulatorRunning = false;
+ g_WiimoteUnexpectedDisconnect = true;
+#if defined(HAVE_WX) && HAVE_WX
+ if (frame) frame->UpdateGUI();
+#endif
+ return;
+ }
+
+ // Debugging
+ {
+ DEBUG_LOG(WII_IPC_WIIMOTE, "Wiimote_ControlChannel");
+ std::string Temp = ArrayToString(data, _Size);
+ DEBUG_LOG(WII_IPC_WIIMOTE, " Data: %s", Temp.c_str());
+ //PanicAlert("Wiimote_ControlChannel");
+ }
+
+ //if (!g_RealWiiMotePresent)
+ WiiMoteEmu::ControlChannel(_channelID, _pData, _Size);
+#if HAVE_WIIUSE
+ if (g_RealWiiMotePresent)
+ WiiMoteReal::ControlChannel(_channelID, _pData, _Size);
+#endif
+
+ DEBUG_LOG(WII_IPC_WIIMOTE, "=============================================================");
+}
+// ==============================
+
+
+// ===================================================
+/* This sends a Data Report from the Wiimote. See SystemTimers.cpp for the documentation of this
+ update. */
+// ----------------
+extern "C" void Wiimote_Update()
+{
+ // Tell us about the update rate, but only about once every second to avoid a major slowdown
+#if defined(HAVE_WX) && HAVE_WX
+ if (frame)
+ {
+ GetUpdateRate();
+ if (g_UpdateWriteScreen > g_UpdateRate)
+ {
+ frame->m_TextUpdateRate->SetLabel(wxString::Format(wxT("Update rate: %03i times/s"), g_UpdateRate));
+ g_UpdateWriteScreen = 0;
+ }
+ g_UpdateWriteScreen++;
+ }
+
+#endif
+ // This functions will send:
+ // Emulated Wiimote: Only data reports 0x30-0x37
+ // Real Wiimote: Both data reports 0x30-0x37 and all other read reports
+ if (!g_Config.bUseRealWiimote || !g_RealWiiMotePresent)
+ WiiMoteEmu::Update();
+#if HAVE_WIIUSE
+ else if (g_RealWiiMotePresent)
+ WiiMoteReal::Update();
+#endif
+
+ // Debugging
+#ifdef _WIN32
+ if( GetAsyncKeyState(VK_HOME) && g_DebugComm ) g_DebugComm = false; // Page Down
+ else if (GetAsyncKeyState(VK_HOME) && !g_DebugComm ) g_DebugComm = true;
+
+ if( GetAsyncKeyState(VK_PRIOR) && g_DebugData ) g_DebugData = false; // Page Up
+ else if (GetAsyncKeyState(VK_PRIOR) && !g_DebugData ) g_DebugData = true;
+
+ if( GetAsyncKeyState(VK_NEXT) && g_DebugAccelerometer ) g_DebugAccelerometer = false; // Home
+ else if (GetAsyncKeyState(VK_NEXT) && !g_DebugAccelerometer ) g_DebugAccelerometer = true;
+
+ if( GetAsyncKeyState(VK_END) && g_DebugCustom ) { g_DebugCustom = false; INFO_LOG(CONSOLE, "Custom Debug: Off\n");} // End
+ else if (GetAsyncKeyState(VK_END) && !g_DebugCustom ) {g_DebugCustom = true; INFO_LOG(CONSOLE, "Custom Debug: Off\n");}
+#endif
+}
+
+extern "C" unsigned int Wiimote_GetAttachedControllers()
+{
+ return 1;
+}
+// ================
+
+
+
+
+//******************************************************************************
+// Supporting functions
+//******************************************************************************
+
+
+
+
+// ----------------------------------------
+// Debugging window
+// ----------
+/*
+void OpenConsole(bool Open)
+{
+ // Close the console window
+ #ifdef _WIN32
+// if (Console::GetHwnd() != NULL && !Open)
+ #else
+ if (false)
+ #endif
+ {
+// Console::Close();
+ // Wait here until we have let go of the button again
+ #ifdef _WIN32
+ while(GetAsyncKeyState(VK_INSERT)) {Sleep(10);}
+ #endif
+ return;
+ }
+
+ // Open the console window
+// Console::Open(140, 1000, "Wiimote"); // give room for 20 rows
+ INFO_LOG(CONSOLE, "\n\nWiimote console opened\n");
+
+ // Move window
+ #ifdef _WIN32
+ //MoveWindow(Console::GetHwnd(), 0,400, 100*8,10*14, true); // small window
+ //MoveWindow(Console::GetHwnd(), 400,0, 100*8,70*14, true); // big window
+// MoveWindow(Console::GetHwnd(), 200,0, 140*8,70*14, true); // big wide window
+ #endif
+ }*/
+// ---------------
+
+// ----------------------------------------
+// Check if Dolphin is in focus
+// ----------
+bool IsFocus()
+{
+#ifdef _WIN32
+ HWND RenderingWindow = g_WiimoteInitialize.hWnd;
+ HWND Parent = GetParent(RenderingWindow);
+ HWND TopLevel = GetParent(Parent);
+ // Allow updates when the config window is in focus to
+ HWND Config = NULL; if (frame) Config = (HWND)frame->GetHWND();
+ // Support both rendering to main window and not
+ if (GetForegroundWindow() == TopLevel || GetForegroundWindow() == RenderingWindow || GetForegroundWindow() == Config)
+ return true;
+ else
+ return false;
+#else
+ return true;
+#endif
+}
+
+// Turn off all extensions
+void DisableExtensions()
+{
+ //g_Config.bMotionPlus = false;
+ g_Config.bNunchuckConnected = false;
+ g_Config.bClassicControllerConnected = false;
+ //g_Config.bBalanceBoard = false;
+ //g_Config.bGuitar = false;
+ //g_Config.bDrums = false;
+}
+
+
+void ReadDebugging(bool Emu, const void* _pData, int Size)
+{
+ //
+ //const u8* data = (const u8*)_pData;
+ //u8* data = (u8*)_pData;
+ // Copy the data to a new location that we know are the right size
+ u8 data[32];
+ memset(data, 0, sizeof(data));
+ memcpy(data, _pData, Size);
+
+ int size;
+ bool DataReport = false;
+ std::string Name, TmpData;
+ switch(data[1])
+ {
+ case WM_STATUS_REPORT: // 0x20
+ size = sizeof(wm_status_report);
+ Name = "WM_STATUS_REPORT";
+ {
+ wm_status_report* pStatus = (wm_status_report*)(data + 2);
+ INFO_LOG(CONSOLE, "\n"
+ "Extension Controller: %i\n"
+ //"Speaker enabled: %i\n"
+ //"IR camera enabled: %i\n"
+ //"LED 1: %i\n"
+ //"LED 2: %i\n"
+ //"LED 3: %i\n"
+ //"LED 4: %i\n"
+ "Battery low: %i\n\n",
+ pStatus->extension,
+ //pStatus->speaker,
+ //pStatus->ir,
+ //(pStatus->leds >> 0),
+ //(pStatus->leds >> 1),
+ //(pStatus->leds >> 2),
+ //(pStatus->leds >> 3),
+ pStatus->battery_low
+ );
+ /* Update the global (for both the real and emulated) extension settings from whatever
+ the real Wiimote use. We will enable the extension from the 0x21 report. */
+ if(!Emu && !pStatus->extension)
+ {
+ DisableExtensions();
+#if defined(HAVE_WX) && HAVE_WX
+ if (frame) frame->UpdateGUI();
+#endif
+ }
+ }
+ break;
+ case WM_READ_DATA_REPLY: // 0x21
+ size = sizeof(wm_read_data_reply);
+ Name = "REPLY";
+ // data[4]: Size and error
+ // data[5, 6]: The registry offset
+
+ // ---------------------------------------------------------------------
+ // Show the extension ID
+ // --------------------------
+ if ((data[4] == 0x10 || data[4] == 0x20 || data[4] == 0x50) && data[5] == 0x00 && (data[6] == 0xfa || data[6] == 0xfe))
+ {
+ if(data[4] == 0x10)
+ TmpData.append(StringFromFormat("Game got the encrypted extension ID: %02x%02x\n", data[7], data[8]));
+ else if(data[4] == 0x50)
+ TmpData.append(StringFromFormat("Game got the encrypted extension ID: %02x%02x%02x%02x%02x%02x\n", data[7], data[8], data[9], data[10], data[11], data[12]));
+
+ // We have already sent the data report so we can safely decrypt it now
+ if(WiiMoteEmu::g_Encryption)
+ {
+ if(data[4] == 0x10)
+ wiimote_decrypt(&WiiMoteEmu::g_ExtKey, &data[0x07], 0x06, (data[4] >> 0x04) + 1);
+ if(data[4] == 0x50)
+ wiimote_decrypt(&WiiMoteEmu::g_ExtKey, &data[0x07], 0x02, (data[4] >> 0x04) + 1);
+ }
+
+ /* Update the global extension settings. Enable the emulated extension from reading
+ what the real Wiimote has connected. To keep the emulated and real Wiimote in sync. */
+ if(data[4] == 0x10)
+ {
+ if (!Emu) DisableExtensions();
+ if (!Emu && data[7] == 0x00 && data[8] == 0x00) g_Config.bNunchuckConnected = true;
+ if (!Emu && data[7] == 0x01 && data[8] == 0x01) g_Config.bClassicControllerConnected = true;
+ g_Config.Save();
+ WiiMoteEmu::UpdateEeprom();
+#if defined(HAVE_WX) && HAVE_WX
+ if (frame) frame->UpdateGUI();
+#endif
+ INFO_LOG(CONSOLE, "%s", TmpData.c_str());
+ INFO_LOG(CONSOLE, "Game got the decrypted extension ID: %02x%02x\n\n", data[7], data[8]);
+ }
+ else if(data[4] == 0x50)
+ {
+ if (!Emu) DisableExtensions();
+ if (!Emu && data[11] == 0x00 && data[12] == 0x00) g_Config.bNunchuckConnected = true;
+ if (!Emu && data[11] == 0x01 && data[12] == 0x01) g_Config.bClassicControllerConnected = true;
+ g_Config.Save();
+ WiiMoteEmu::UpdateEeprom();
+#if defined(HAVE_WX) && HAVE_WX
+ if (frame) frame->UpdateGUI();
+#endif
+ INFO_LOG(CONSOLE, "%s", TmpData.c_str());
+ INFO_LOG(CONSOLE, "Game got the decrypted extension ID: %02x%02x%02x%02x%02x%02x\n\n", data[7], data[8], data[9], data[10], data[11], data[12]);
+ }
+ }
+ // ---------------------------------------------
+
+ // ---------------------------------------------------------------------
+ // Show the Wiimote neutral values
+ // --------------------------
+ /* The only difference between the Nunchuck and Wiimote that we go after is calibration here is
+ the offset in memory. If needed we can check the preceding 0x17 request to. */
+ if(data[4] == 0xf0 && data[5] == 0x00 && data[6] == 0x10)
+ {
+ if(data[6] == 0x10)
+ {
+ INFO_LOG(CONSOLE, "\nGame got the Wiimote calibration:\n");
+ INFO_LOG(CONSOLE, "Cal_zero.x: %i\n", data[7 + 6]);
+ INFO_LOG(CONSOLE, "Cal_zero.y: %i\n", data[7 + 7]);
+ INFO_LOG(CONSOLE, "Cal_zero.z: %i\n", data[7 + 8]);
+ INFO_LOG(CONSOLE, "Cal_g.x: %i\n", data[7 + 10]);
+ INFO_LOG(CONSOLE, "Cal_g.y: %i\n", data[7 + 11]);
+ INFO_LOG(CONSOLE, "Cal_g.z: %i\n", data[7 +12]);
+ }
+ }
+ // ---------------------------------------------
+
+ // ---------------------------------------------------------------------
+ // Show the Nunchuck neutral values
+ // --------------------------
+ if(data[4] == 0xf0 && data[5] == 0x00 && (data[6] == 0x20 || data[6] == 0x30))
+ {
+ // Save the encrypted data
+ TmpData = StringFromFormat("Read[%s] (enc): %s\n", (Emu ? "Emu" : "Real"), ArrayToString(data, size + 2, 0, 30).c_str());
+
+ // We have already sent the data report so we can safely decrypt it now
+ if(WiiMoteEmu::g_Encryption)
+ wiimote_decrypt(&WiiMoteEmu::g_ExtKey, &data[0x07], 0x00, (data[4] >> 0x04) + 1);
+
+ if (g_Config.bNunchuckConnected)
+ {
+ INFO_LOG(CONSOLE, "\nGame got the Nunchuck calibration:\n");
+ INFO_LOG(CONSOLE, "Cal_zero.x: %i\n", data[7 + 0]);
+ INFO_LOG(CONSOLE, "Cal_zero.y: %i\n", data[7 + 1]);
+ INFO_LOG(CONSOLE, "Cal_zero.z: %i\n", data[7 + 2]);
+ INFO_LOG(CONSOLE, "Cal_g.x: %i\n", data[7 + 4]);
+ INFO_LOG(CONSOLE, "Cal_g.y: %i\n", data[7 + 5]);
+ INFO_LOG(CONSOLE, "Cal_g.z: %i\n", data[7 + 6]);
+ INFO_LOG(CONSOLE, "Js.Max.x: %i\n", data[7 + 8]);
+ INFO_LOG(CONSOLE, "Js.Min.x: %i\n", data[7 + 9]);
+ INFO_LOG(CONSOLE, "Js.Center.x: %i\n", data[7 + 10]);
+ INFO_LOG(CONSOLE, "Js.Max.y: %i\n", data[7 + 11]);
+ INFO_LOG(CONSOLE, "Js.Min.y: %i\n", data[7 + 12]);
+ INFO_LOG(CONSOLE, "JS.Center.y: %i\n\n", data[7 + 13]);
+ }
+ else // g_Config.bClassicControllerConnected
+ {
+ INFO_LOG(CONSOLE, "\nGame got the Classic Controller calibration:\n");
+ INFO_LOG(CONSOLE, "Lx.Max: %i\n", data[7 + 0]);
+ INFO_LOG(CONSOLE, "Lx.Min: %i\n", data[7 + 1]);
+ INFO_LOG(CONSOLE, "Lx.Center: %i\n", data[7 + 2]);
+ INFO_LOG(CONSOLE, "Ly.Max: %i\n", data[7 + 3]);
+ INFO_LOG(CONSOLE, "Ly.Min: %i\n", data[7 + 4]);
+ INFO_LOG(CONSOLE, "Ly.Center: %i\n", data[7 + 5]);
+ INFO_LOG(CONSOLE, "Rx.Max.x: %i\n", data[7 + 6]);
+ INFO_LOG(CONSOLE, "Rx.Min.x: %i\n", data[7 + 7]);
+ INFO_LOG(CONSOLE, "Rx.Center.x: %i\n", data[7 + 8]);
+ INFO_LOG(CONSOLE, "Ry.Max.y: %i\n", data[7 + 9]);
+ INFO_LOG(CONSOLE, "Ry.Min: %i\n", data[7 + 10]);
+ INFO_LOG(CONSOLE, "Ry.Center: %i\n\n", data[7 + 11]);
+ INFO_LOG(CONSOLE, "Lt.Neutral: %i\n", data[7 + 12]);
+ INFO_LOG(CONSOLE, "Rt.Neutral %i\n\n", data[7 + 13]);
+ }
+
+ // Save the values if they come from the real Wiimote
+ if (!Emu)
+ {
+ // Save the values from the Nunchuck
+ if(data[7 + 0] != 0xff)
+ {
+ memcpy(WiiMoteEmu::g_RegExt + 0x20, &data[7], 0x10);
+ memcpy(WiiMoteEmu::g_RegExt + 0x30, &data[7], 0x10);
+
+ }
+ // Save the default values that should work with Wireless Nunchucks
+ else
+ {
+ WiiMoteEmu::SetDefaultExtensionRegistry();
+ }
+ WiiMoteEmu::UpdateEeprom();
+ }
+ // We got a third party nunchuck
+ else if(data[7 + 0] == 0xff)
+ {
+ memcpy(WiiMoteEmu::g_RegExt + 0x20, WiiMoteEmu::wireless_nunchuck_calibration, sizeof(WiiMoteEmu::wireless_nunchuck_calibration));
+ memcpy(WiiMoteEmu::g_RegExt + 0x30, WiiMoteEmu::wireless_nunchuck_calibration, sizeof(WiiMoteEmu::wireless_nunchuck_calibration));
+ }
+
+ // Show the encrypted data
+ INFO_LOG(CONSOLE, "%s", TmpData.c_str());
+ }
+ // ---------------------------------------------
+
+ break;
+ case WM_WRITE_DATA_REPLY: // 0x22
+ size = sizeof(wm_acknowledge) - 1;
+ Name = "REPLY";
+ break;
+ case WM_REPORT_CORE: // 0x30-0x37
+ size = sizeof(wm_report_core);
+ DataReport = true;
+ break;
+ case WM_REPORT_CORE_ACCEL:
+ size = sizeof(wm_report_core_accel);
+ DataReport = true;
+ break;
+ case WM_REPORT_CORE_EXT8:
+ size = sizeof(wm_report_core_accel_ir12);
+ DataReport = true;
+ break;
+ case WM_REPORT_CORE_ACCEL_IR12:
+ size = sizeof(wm_report_core_accel_ir12);
+ DataReport = true;
+ break;
+ case WM_REPORT_CORE_EXT19:
+ size = sizeof(wm_report_core_accel_ext16);
+ DataReport = true;
+ break;
+ case WM_REPORT_CORE_ACCEL_EXT16:
+ size = sizeof(wm_report_core_accel_ext16);
+ DataReport = true;
+ break;
+ case WM_REPORT_CORE_IR10_EXT9:
+ size = sizeof(wm_report_core_accel_ir10_ext6);
+ DataReport = true;
+ break;
+ case WM_REPORT_CORE_ACCEL_IR10_EXT6:
+ size = sizeof(wm_report_core_accel_ir10_ext6);
+ DataReport = true;
+ break;
+ default:
+ //PanicAlert("%s ReadDebugging: Unknown channel 0x%02x", (Emu ? "Emu" : "Real"), data[1]);
+ INFO_LOG(CONSOLE, "%s ReadDebugging: Unknown channel 0x%02x", (Emu ? "Emu" : "Real"), data[1]);
+ return;
+ }
+
+ if (!DataReport && g_DebugComm)
+ {
+ std::string TmpData = ArrayToString(data, size + 2, 0, 30);
+ //LOGV(WII_IPC_WIIMOTE, 3, " Data: %s", Temp.c_str());
+ INFO_LOG(CONSOLE, "Read[%s] %s: %s\n", (Emu ? "Emu" : "Real"), Name.c_str(), TmpData.c_str()); // No timestamp
+ //INFO_LOG(CONSOLE, " (%s): %s\n", Tm(true).c_str(), Temp.c_str()); // Timestamp
+ }
+
+ if (DataReport && g_DebugData)
+ {
+ // Decrypt extension data
+ if(WiiMoteEmu::g_ReportingMode == 0x37)
+ wiimote_decrypt(&WiiMoteEmu::g_ExtKey, &data[17], 0x00, 0x06);
+ if(WiiMoteEmu::g_ReportingMode == 0x35)
+ wiimote_decrypt(&WiiMoteEmu::g_ExtKey, &data[7], 0x00, 0x06);
+
+ // Produce string
+ //std::string TmpData = ArrayToString(data, size + 2, 0, 30);
+ //LOGV(WII_IPC_WIIMOTE, 3, " Data: %s", Temp.c_str());
+ std::string TmpCore = "", TmpAccel = "", TmpIR = "", TmpExt = "", CCData = "";
+ TmpCore = StringFromFormat(
+ "%02x %02x %02x %02x",
+ data[0], data[1], data[2], data[3]); // Header and core buttons
+
+ TmpAccel = StringFromFormat(
+ "%03i %03i %03i",
+ data[4], data[5], data[6]); // Wiimote accelerometer
+
+ if (data[1] == 0x33) // WM_REPORT_CORE_ACCEL_IR12
+ {
+ TmpIR = StringFromFormat(
+ "%02x %02x %02x %02x %02x %02x"
+ " %02x %02x %02x %02x %02x %02x",
+ data[7], data[8], data[9], data[10], data[11], data[12],
+ data[13], data[14], data[15], data[16], data[17], data[18]);
+ }
+ if (data[1] == 0x35) // WM_REPORT_CORE_ACCEL_EXT16
+ {
+ TmpExt = StringFromFormat(
+ "%02x %02x %02x %02x %02x %02x",
+ data[7], data[8], // Nunchuck stick
+ data[9], data[10], data[11], // Nunchuck Accelerometer
+ data[12]); // Nunchuck buttons
+
+ CCData = WiiMoteEmu::CCData2Values(&data[7]);
+ }
+ if (data[1] == 0x37) // WM_REPORT_CORE_ACCEL_IR10_EXT6
+ {
+ TmpIR = StringFromFormat(
+ "%02x %02x %02x %02x %02x"
+ " %02x %02x %02x %02x %02x",
+ data[7], data[8], data[9], data[10], data[11],
+ data[12], data[13], data[14], data[15], data[16]);
+ TmpExt = StringFromFormat(
+ "%02x %02x %02x %02x %02x %02x",
+ data[17], data[18], // Nunchuck stick
+ data[19], data[20], data[21], // Nunchuck Accelerometer
+ data[22]); // Nunchuck buttons
+ CCData = WiiMoteEmu::CCData2Values(&data[17]);
+ }
+
+
+ // ---------------------------------------------
+ // Calculate the Wiimote roll and pitch in degrees
+ // -----------
+ int Roll, Pitch, RollAdj, PitchAdj;
+ WiiMoteEmu::PitchAccelerometerToDegree(data[4], data[5], data[6], Roll, Pitch, RollAdj, PitchAdj);
+ std::string RollPitch = StringFromFormat("%s %s %s %s",
+ (Roll >= 0) ? StringFromFormat(" %03i", Roll).c_str() : StringFromFormat("%04i", Roll).c_str(),
+ (Pitch >= 0) ? StringFromFormat(" %03i", Pitch).c_str() : StringFromFormat("%04i", Pitch).c_str(),
+ (RollAdj == Roll) ? " " : StringFromFormat("%04i*", RollAdj).c_str(),
+ (PitchAdj == Pitch) ? " " : StringFromFormat("%04i*", PitchAdj).c_str());
+ // -------------------------
+
+ // ---------------------------------------------
+ // Test the angles to x, y, z values formula by calculating the values back and forth
+ // -----------
+ /* //Console::ClearScreen();
+ // Show a test of our calculations
+ WiiMoteEmu::TiltTest(data[4], data[5], data[6]);
+ u8 x, y, z;
+ WiiMoteEmu::Tilt(x, y, z);
+ WiiMoteEmu::TiltTest(x, y, z);*/
+ // -------------------------
+
+ // ---------------------------------------------
+ // Show the number of g forces on the axes
+ // -----------
+ float Gx = WiiMoteEmu::AccelerometerToG((float)data[4], (float)g_wm.cal_zero.x, (float)g_wm.cal_g.x);
+ float Gy = WiiMoteEmu::AccelerometerToG((float)data[5], (float)g_wm.cal_zero.y, (float)g_wm.cal_g.y);
+ float Gz = WiiMoteEmu::AccelerometerToG((float)data[6], (float)g_wm.cal_zero.z, (float)g_wm.cal_g.z);
+ std::string GForce = StringFromFormat("%s %s %s",
+ ((int)Gx >= 0) ? StringFromFormat(" %i", (int)Gx).c_str() : StringFromFormat("%i", (int)Gx).c_str(),
+ ((int)Gy >= 0) ? StringFromFormat(" %i", (int)Gy).c_str() : StringFromFormat("%i", (int)Gy).c_str(),
+ ((int)Gz >= 0) ? StringFromFormat(" %i", (int)Gz).c_str() : StringFromFormat("%i", (int)Gz).c_str());
+ // -------------------------
+
+ // ---------------------------------------------
+ // Calculate the IR data
+ // -----------
+ if (data[1] == WM_REPORT_CORE_ACCEL_IR10_EXT6) WiiMoteEmu::IRData2DotsBasic(&data[7]); else WiiMoteEmu::IRData2Dots(&data[7]);
+ std::string IRData;
+ // Create a shortcut
+ struct WiiMoteEmu::SDot* Dot = WiiMoteEmu::g_Wm.IR.Dot;
+ for (int i = 0; i < 4; ++i)
+ {
+ if(Dot[i].Visible)
+ IRData += StringFromFormat("[%i] X:%04i Y:%04i Size:%i ", Dot[i].Order, Dot[i].Rx, Dot[i].Ry, Dot[i].Size);
+ else
+ IRData += StringFromFormat("[%i]", Dot[i].Order);
+ }
+ // Dot distance
+ IRData += StringFromFormat(" | Distance:%i", WiiMoteEmu::g_Wm.IR.Distance);
+ // -------------------------
+
+ // Classic Controller data
+ INFO_LOG(CONSOLE, "Read[%s]: %s | %s | %s | %s | %s\n", (Emu ? "Emu" : "Real"),
+ TmpCore.c_str(), TmpAccel.c_str(), TmpIR.c_str(), TmpExt.c_str(), CCData.c_str());
+ // Formatted data only
+ //INFO_LOG(CONSOLE, "Read[%s]: 0x%02x | %s | %s | %s\n", (Emu ? "Emu" : "Real"), data[1], RollPitch.c_str(), GForce.c_str(), IRData.c_str());
+ // IR data
+ //INFO_LOG(CONSOLE, "Read[%s]: %s | %s\n", (Emu ? "Emu" : "Real"), TmpData.c_str(), IRData.c_str());
+ // Accelerometer data
+ //INFO_LOG(CONSOLE, "Read[%s]: %s | %s | %s | %s | %s | %s | %s\n", (Emu ? "Emu" : "Real"),
+ // TmpCore.c_str(), TmpAccel.c_str(), TmpIR.c_str(), TmpExt.c_str(), RollPitch.c_str(), GForce.c_str(), CCData.c_str());
+ // Timestamp
+ //INFO_LOG(CONSOLE, " (%s): %s\n", Tm(true).c_str(), Temp.c_str());
+
+ }
+ if(g_DebugAccelerometer)
+ {
+ // Accelerometer only
+ // Console::ClearScreen();
+ INFO_LOG(CONSOLE, "Accel x, y, z: %03u %03u %03u\n", data[4], data[5], data[6]);
+ }
+}
+
+
+void InterruptDebugging(bool Emu, const void* _pData)
+{
+ //
+ const u8* data = (const u8*)_pData;
+
+ std::string Name;
+ int size;
+ u16 SampleValue;
+ bool SoundData = false;
+
+ if (g_DebugComm) Name += StringFromFormat("Write[%s] ", (Emu ? "Emu" : "Real"));
+
+ switch(data[1])
+ {
+ case 0x10:
+ size = 4; // I don't know the size
+ if (g_DebugComm) Name.append("0x10");
+ break;
+ case WM_LEDS: // 0x11
+ size = sizeof(wm_leds);
+ if (g_DebugComm) Name.append("WM_LEDS");
+ break;
+ case WM_DATA_REPORTING: // 0x12
+ size = sizeof(wm_data_reporting);
+ if (g_DebugComm) Name.append("WM_DATA_REPORTING");
+ break;
+ case WM_REQUEST_STATUS: // 0x15
+ size = sizeof(wm_request_status);
+ if (g_DebugComm) Name.append("WM_REQUEST_STATUS");
+ break;
+ case WM_WRITE_DATA: // 0x16
+ if (g_DebugComm) Name.append("WM_WRITE_DATA");
+ size = sizeof(wm_write_data);
+ // data[2]: The address space 0, 1 or 2
+ // data[3]: The registry type
+ // data[5]: The registry offset
+ // data[6]: The number of bytes
+ switch(data[2] >> 0x01)
+ {
+ case WM_SPACE_EEPROM:
+ if (g_DebugComm) Name.append(" REG_EEPROM"); break;
+ case WM_SPACE_REGS1:
+ case WM_SPACE_REGS2:
+ switch(data[3])
+ {
+ case 0xa2:
+ // data[8]: FF, 0x00 or 0x40
+ // data[9, 10]: RR RR, 0xd007 or 0x401f
+ // data[11]: VV, 0x00 to 0xff or 0x00 to 0x40
+ if (g_DebugComm)
+ {
+ Name.append(" REG_SPEAKER");
+ if(data[6] == 7)
+ {
+ INFO_LOG(CONSOLE, "\nSound configuration:\n");
+ if(data[8] == 0x00)
+ {
+ memcpy(&SampleValue, &data[9], 2);
+ INFO_LOG(CONSOLE, " Data format: 4-bit ADPCM (%i Hz)\n", 6000000 / SampleValue);
+ INFO_LOG(CONSOLE, " Volume: %02i%%\n\n", (data[11] / 0x40) * 100);
+ }
+ else if (data[8] == 0x40)
+ {
+ memcpy(&SampleValue, &data[9], 2);
+ INFO_LOG(CONSOLE, " Data format: 8-bit PCM (%i Hz)\n", 12000000 / SampleValue);
+ INFO_LOG(CONSOLE, " Volume: %02i%%\n\n", (data[11] / 0xff) * 100);
+ }
+ }
+ }
+ break;
+ case 0xa4:
+ if (g_DebugComm) Name.append(" REG_EXT");
+ // Update the encryption mode
+ if (data[3] == 0xa4 && data[5] == 0xf0)
+ {
+ if (data[7] == 0xaa)
+ WiiMoteEmu::g_Encryption = true;
+ else if (data[7] == 0x55)
+ WiiMoteEmu::g_Encryption = false;
+ INFO_LOG(CONSOLE, "\nExtension enryption turned %s\n\n", WiiMoteEmu::g_Encryption ? "On" : "Off");
+ }
+ break;
+ case 0xb0:
+ if (g_DebugComm) Name.append(" REG_IR"); break;
+ }
+ break;
+ }
+ break;
+ case WM_READ_DATA: // 0x17
+ size = sizeof(wm_read_data);
+ // data[2]: The address space 0, 1 or 2
+ // data[3]: The registry type
+ // data[5]: The registry offset
+ // data[7]: The number of bytes, 6 and 7 together
+ if (g_DebugComm) Name.append("WM_READ_DATA");
+ switch(data[2] >> 0x01)
+ {
+ case WM_SPACE_EEPROM:
+ if (g_DebugComm) Name.append(" REG_EEPROM"); break;
+ case WM_SPACE_REGS1:
+ case WM_SPACE_REGS2:
+ switch(data[3])
+ {
+ case 0xa2:
+ if (g_DebugComm) Name.append(" REG_SPEAKER"); break;
+ case 0xa4:
+ if (g_DebugComm) Name.append(" REG_EXT"); break;
+ case 0xb0:
+ if (g_DebugComm) Name.append(" REG_IR"); break;
+ }
+ break;
+ }
+ break;
+
+ case WM_IR_PIXEL_CLOCK: // 0x13
+ case WM_IR_LOGIC: // 0x1a
+ if (g_DebugComm) Name.append("WM_IR");
+ size = 1;
+ break;
+ case WM_SPEAKER_ENABLE: // 0x14
+ case WM_SPEAKER_MUTE: // 0x19
+ if (g_DebugComm) Name.append("WM_SPEAKER");
+ size = 1;
+ if(data[1] == 0x14) {
+ INFO_LOG(CONSOLE, "\nSpeaker %s\n\n", (data[2] == 0x06) ? "On" : "Off");
+ } else if(data[1] == 0x19) {
+ INFO_LOG(CONSOLE, "\nSpeaker %s\n\n", (data[2] == 0x06) ? "Muted" : "Unmuted");
+ }
+ break;
+ case WM_WRITE_SPEAKER_DATA: // 0x18
+ if (g_DebugComm) Name.append("WM_SPEAKER_DATA");
+ size = 21;
+ break;
+
+ default:
+ size = 15;
+ INFO_LOG(CONSOLE, "%s InterruptDebugging: Unknown channel 0x%02x", (Emu ? "Emu" : "Real"), data[1]);
+ break;
+ }
+ if (g_DebugComm && !SoundData)
+ {
+ std::string Temp = ArrayToString(data, size + 2, 0, 30);
+ //LOGV(WII_IPC_WIIMOTE, 3, " Data: %s", Temp.c_str());
+ INFO_LOG(CONSOLE, "%s: %s\n", Name.c_str(), Temp.c_str()); // No timestamp
+ //INFO_LOG(CONSOLE, " (%s): %s\n", Tm(true).c_str(), Temp.c_str()); // Timestamp
+ }
+ if (g_DebugSoundData && SoundData)
+ {
+ std::string Temp = ArrayToString(data, size + 2, 0, 30);
+ //LOGV(WII_IPC_WIIMOTE, 3, " Data: %s", Temp.c_str());
+ INFO_LOG(CONSOLE, "%s: %s\n", Name.c_str(), Temp.c_str()); // No timestamp
+ //INFO_LOG(CONSOLE, " (%s): %s\n", Tm(true).c_str(), Temp.c_str()); // Timestamp
+ }
+
+}
+
+
+/* Returns a timestamp with three decimals for precise time comparisons. The return format is
+ of the form seconds.milleseconds for example 1234.123. The leding seconds have no particular meaning
+ but are just there to enable use to tell if we have entered a new second or now. */
+// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
+double GetDoubleTime()
+{
+#if defined(HAVE_WX) && HAVE_WX
+ wxDateTime datetime = wxDateTime::UNow(); // Get timestamp
+ u64 TmpSeconds = Common::Timer::GetTimeSinceJan1970(); // Get continous timestamp
+
+ /* Remove a few years. We only really want enough seconds to make sure that we are
+ detecting actual actions, perhaps 60 seconds is enough really, but I leave a
+ year of seconds anyway, in case the user's clock is incorrect or something like that */
+ TmpSeconds = TmpSeconds - (38 * 365 * 24 * 60 * 60);
+
+ //if (TmpSeconds < 0) return 0; // Check the the user's clock is working somewhat
+
+ u32 Seconds = (u32)TmpSeconds; // Make a smaller integer that fits in the double
+ double ms = datetime.GetMillisecond() / 1000.0;
+ double TmpTime = Seconds + ms;
+ return TmpTime;
+#endif
+}
+
+/* Calculate the current update frequency. Calculate the time between ten updates, and average
+ five such rates. If we assume there are 60 updates per second if the game is running at full
+ speed then we get this measure on average once every second. The reason to have a few updates
+ between each measurement is becase the milliseconds may not be perfectly accurate and may return
+ the same time even when a milliseconds has actually passed, for example.*/
+int GetUpdateRate()
+{
+#if defined(HAVE_WX) && HAVE_WX
+ if(g_UpdateCounter == 10)
+ {
+ // Erase the old ones
+ if(g_UpdateTimeList.size() == 5) g_UpdateTimeList.erase(g_UpdateTimeList.begin() + 0);
+
+ // Calculate the time and save it
+ int Time = (int)(10 / (GetDoubleTime() - g_UpdateTime));
+ g_UpdateTimeList.push_back(Time);
+ //INFO_LOG(CONSOLE, "Time: %i %f\n", Time, GetDoubleTime());
+
+ int TotalTime = 0;
+ for (int i = 0; i < (int)g_UpdateTimeList.size(); i++)
+ TotalTime += g_UpdateTimeList.at(i);
+ g_UpdateRate = TotalTime / 5;
+
+ // Write the new update time
+ g_UpdateTime = GetDoubleTime();
+
+ g_UpdateCounter = 0;
+ }
+
+ g_UpdateCounter++;
+
+ return g_UpdateRate;
+#else
+ return 0;
+#endif
+}
+
+void DoInitialize()
+{
+ // Open console
+ //OpenConsole(true);
+
+ // Run this first so that WiiMoteReal::Initialize() overwrites g_Eeprom
+ WiiMoteEmu::Initialize();
+
+ /* We will run WiiMoteReal::Initialize() even if we are not using a real wiimote,
+ to check if there is a real wiimote connected. We will initiate wiiuse.dll, but
+ we will return before creating a new thread for it if we find no real Wiimotes.
+ Then g_RealWiiMotePresent will also be false. This function call will be done
+ instantly whether there is a real Wiimote connected or not. It takes no time for
+ Wiiuse to check for connected Wiimotes. */
+ #if HAVE_WIIUSE
+ if (g_Config.bConnectRealWiimote) WiiMoteReal::Initialize();
+ #endif
+}
+
+
diff --git a/Source/Plugins/Plugin_Wiimote-testing/Src/main.h b/Source/Plugins/Plugin_Wiimote-testing/Src/main.h
new file mode 100644
index 0000000000..8d4481e8a2
--- /dev/null
+++ b/Source/Plugins/Plugin_Wiimote-testing/Src/main.h
@@ -0,0 +1,109 @@
+// Copyright (C) 2003-2008 Dolphin Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official SVN repository and contact information can be found at
+// http://code.google.com/p/dolphin-emu/
+
+#ifndef MAIN_H
+#define MAIN_H
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Includes
+// ŻŻŻŻŻŻŻŻŻŻŻŻŻ
+#include // System
+////////////////////////////////
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Definitions and declarations
+// ŻŻŻŻŻŻŻŻŻ
+#ifdef _WIN32
+#define sleep(x) Sleep(x)
+#else
+#define sleep(x) usleep(x*1000)
+#endif
+
+
+void DoInitialize();
+double GetDoubleTime();
+int GetUpdateRate();
+void InterruptDebugging(bool Emu, const void* _pData);
+void ReadDebugging(bool Emu, const void* _pData, int Size);
+bool IsFocus();
+
+
+// Movement recording
+#define RECORDING_ROWS 15
+#define WM_RECORDING_WIIMOTE 0
+#define WM_RECORDING_NUNCHUCK 1
+#define WM_RECORDING_IR 2
+struct SRecording
+{
+ int x;
+ int y;
+ int z;
+ double Time;
+ u8 IR[12];
+};
+struct SRecordingAll
+{
+ std::vector Recording;
+ int HotKeySwitch, HotKeyWiimote, HotKeyNunchuck, HotKeyIR;
+ int PlaybackSpeed;
+ int IRBytes;
+};
+
+#ifndef EXCLUDEMAIN_H
+ // General
+ extern bool g_EmulatorRunning;
+ extern u32 g_ISOId;
+ extern bool g_FrameOpen;
+ extern bool g_RealWiiMotePresent;
+ extern bool g_RealWiiMoteInitialized;
+ extern bool g_EmulatedWiiMoteInitialized;
+ extern bool g_WiimoteUnexpectedDisconnect;
+ #ifdef _WIN32
+ extern HWND g_ParentHWND;
+ #endif
+
+ // Settings
+ extern accel_cal g_wm;
+ extern nu_cal g_nu;
+ extern cc_cal g_cc;
+
+ // Debugging
+ extern bool g_DebugAccelerometer;
+ extern bool g_DebugData;
+ extern bool g_DebugComm;
+ extern bool g_DebugSoundData;
+ extern bool g_DebugCustom;
+
+ // Update speed
+ extern int g_UpdateCounter;
+ extern double g_UpdateTime;
+ extern int g_UpdateWriteScreen;
+ extern int g_UpdateRate;
+ extern std::vector g_UpdateTimeList;
+
+ // Movement recording
+ extern std::vector VRecording;
+
+ //#if defined(HAVE_WX) && HAVE_WX && defined(__CONFIGDIALOG_h__)
+ // extern ConfigDialog *frame;
+ //#endif
+#endif
+////////////////////////////////
+
+
+#endif // MAIN_H
diff --git a/Source/Plugins/Plugin_Wiimote-testing/Src/wiimote_hid.h b/Source/Plugins/Plugin_Wiimote-testing/Src/wiimote_hid.h
new file mode 100644
index 0000000000..1a98dff196
--- /dev/null
+++ b/Source/Plugins/Plugin_Wiimote-testing/Src/wiimote_hid.h
@@ -0,0 +1,330 @@
+// Copyright (C) 2003-2008 Dolphin Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official SVN repository and contact information can be found at
+// http://code.google.com/p/dolphin-emu/
+
+#ifndef WIIMOTE_HID_H
+#define WIIMOTE_HID_H
+
+#include
+
+#ifdef _MSC_VER
+#pragma warning(disable:4200)
+#endif
+#pragma pack(push, 1)
+
+// Source: HID_010_SPC_PFL/1.0 (official HID specification)
+
+struct hid_packet {
+ u8 param : 4;
+ u8 type : 4;
+ u8 data[0];
+};
+
+#define HID_TYPE_HANDSHAKE 0
+#define HID_TYPE_SET_REPORT 5
+#define HID_TYPE_DATA 0xA
+
+#define HID_HANDSHAKE_SUCCESS 0
+
+#define HID_PARAM_INPUT 1
+#define HID_PARAM_OUTPUT 2
+
+//source: http://wiibrew.org/wiki/Wiimote
+
+struct wm_report {
+ u8 channel;
+ u8 data[0];
+};
+
+#define WM_RUMBLE 0x10
+#define WM_LEDS 0x11
+struct wm_leds {
+ u8 rumble : 1;
+ u8 : 3;
+ u8 leds : 4;
+};
+
+#define WM_DATA_REPORTING 0x12
+struct wm_data_reporting {
+ u8 rumble : 1;
+ u8 continuous : 1;
+ u8 all_the_time : 1;
+ u8 : 5;
+ u8 mode;
+};
+
+#define WM_IR_PIXEL_CLOCK 0x13
+#define WM_IR_LOGIC 0x1A
+
+#define WM_REQUEST_STATUS 0x15
+struct wm_request_status {
+ u8 rumble : 1;
+ u8 : 7;
+};
+
+#define WM_STATUS_REPORT 0x20
+struct wm_status_report {
+ u8 padding1[2]; // two 00
+ u8 battery_low : 1;
+ u8 extension : 1;
+ u8 speaker : 1;
+ u8 ir : 1;
+ u8 leds : 4;
+ u8 padding2[2]; // two 00
+ u8 battery;
+};
+
+#define WM_WRITE_DATA 0x16
+struct wm_write_data
+{
+ u8 rumble : 1;
+ u8 space : 2; //see WM_SPACE_*
+ u8 : 5;
+ u8 address[3];
+ u8 size;
+ u8 data[16];
+};
+
+#define WM_WRITE_DATA_REPLY 0x22 //empty, afaik
+struct wm_acknowledge
+{
+ u8 Channel;
+ u8 unk0; // Core buttons state (wm_core), can be zero
+ u8 unk1;
+ u8 reportID;
+ u8 errorID;
+};
+
+#define WM_READ_DATA 0x17
+struct wm_read_data {
+ u8 rumble : 1;
+ u8 space : 2; //see WM_SPACE_*
+ u8 : 5;
+ u8 address[3];
+ u8 size[2];
+};
+
+#define WM_SPACE_EEPROM 0
+#define WM_SPACE_REGS1 1
+#define WM_SPACE_REGS2 2
+#define WM_SPACE_INVALID 3
+
+#define WM_READ_DATA_REPLY 0x21
+struct wm_read_data_reply {
+ u16 buttons;
+ u8 error : 4; //see WM_RDERR_*
+ u8 size : 4;
+ u16 address;
+ u8 data[16];
+};
+
+#define WM_RDERR_WOREG 7
+#define WM_RDERR_NOMEM 8
+
+struct wm_core {
+ u8 left : 1;
+ u8 right : 1;
+ u8 down : 1;
+ u8 up : 1;
+ u8 plus : 1;
+ u8 : 3;
+ u8 two : 1;
+ u8 one : 1;
+ u8 b : 1;
+ u8 a : 1;
+ u8 minus : 1;
+ u8 : 2;
+ u8 home : 1;
+};
+
+struct wm_accel {
+ u8 x, y, z;
+};
+
+// Four bytes for two objects. Filled with 0xFF if empty
+struct wm_ir_basic
+{
+ u8 x1;
+ u8 y1;
+ u8 x2Hi : 2;
+ u8 y2Hi : 2;
+ u8 x1Hi : 2;
+ u8 y1Hi : 2;
+ u8 x2;
+ u8 y2;
+};
+
+// Three bytes for one object
+struct wm_ir_extended
+{
+ u8 x;
+ u8 y;
+ u8 size : 4;
+ u8 xHi : 2;
+ u8 yHi : 2;
+};
+
+struct wm_extension
+{
+ u8 jx; // joystick x, y
+ u8 jy;
+ u8 ax; // accelerometer
+ u8 ay;
+ u8 az;
+ u8 bt; // buttons
+};
+
+struct wm_cc_4
+{
+ u8 padding : 1;
+ u8 bRT : 1;
+ u8 bP : 1;
+ u8 bH : 1;
+ u8 bM : 1;
+ u8 bLT : 1;
+ u8 bdD : 1;
+ u8 bdR : 1;
+};
+
+struct wm_cc_5
+{
+ u8 bdU : 1;
+ u8 bdL : 1;
+ u8 bZR : 1;
+ u8 bX : 1;
+ u8 bA : 1;
+ u8 bY : 1;
+ u8 bB : 1;
+ u8 bZL : 1;
+};
+
+struct wm_classic_extension
+{
+ u8 Lx : 6; // byte 0
+ u8 Rx3 : 2;
+ u8 Ly : 6; // byte 1
+ u8 Rx2 : 2;
+ u8 Ry : 5; // byte 2
+ u8 lT2 : 2;
+ u8 Rx : 1;
+ u8 rT : 5; // byte 3
+ u8 lT : 3;
+ wm_cc_4 b1; // byte 4
+ wm_cc_5 b2; // byte 5
+};
+
+//******************************************************************************
+// Data reports
+//******************************************************************************
+
+#define WM_REPORT_CORE 0x30
+struct wm_report_core {
+ wm_core c;
+};
+
+#define WM_REPORT_CORE_ACCEL 0x31
+struct wm_report_core_accel {
+ wm_core c;
+ wm_accel a;
+};
+
+#define WM_REPORT_CORE_EXT8 0x32
+
+#define WM_REPORT_CORE_ACCEL_IR12 0x33
+struct wm_report_core_accel_ir12 {
+ wm_core c;
+ wm_accel a;
+ wm_ir_extended ir[4];
+};
+
+#define WM_REPORT_CORE_EXT19 0x34
+#define WM_REPORT_CORE_ACCEL_EXT16 0x35
+struct wm_report_core_accel_ext16
+{
+ wm_core c;
+ wm_accel a;
+ wm_extension ext;
+ //wm_ir_basic ir[2];
+ u8 pad[10];
+
+};
+
+#define WM_REPORT_CORE_IR10_EXT9 0x36
+
+#define WM_REPORT_CORE_ACCEL_IR10_EXT6 0x37
+struct wm_report_core_accel_ir10_ext6
+{
+ wm_core c;
+ wm_accel a;
+ wm_ir_basic ir[2];
+ //u8 ext[6];
+ wm_extension ext;
+};
+
+#define WM_REPORT_EXT21 0x3d // never used?
+struct wm_report_ext21
+{
+ u8 ext[21];
+};
+
+#define WM_REPORT_INTERLEAVE1 0x3e
+#define WM_REPORT_INTERLEAVE2 0x3f
+
+#define WM_SPEAKER_ENABLE 0x14
+#define WM_SPEAKER_MUTE 0x19
+#define WM_WRITE_SPEAKER_DATA 0x18
+
+
+//******************************************************************************
+// Custom structs
+//******************************************************************************
+
+/**
+ * @struct accel_t
+ * @brief Accelerometer struct. For any device with an accelerometer.
+ */
+struct accel_cal
+{
+ wm_accel cal_zero; /**< zero calibration */
+ wm_accel cal_g; /**< 1g difference around 0cal */
+};
+
+struct nu_js {
+ u8 max, min, center;
+};
+struct cc_trigger {
+ u8 neutral;
+};
+struct nu_cal
+{
+ wm_accel cal_zero; // zero calibratio
+ wm_accel cal_g; // g size
+ nu_js jx; //
+ nu_js jy; //
+};
+struct cc_cal
+{
+ nu_js Lx; //
+ nu_js Ly; //
+ nu_js Rx; //
+ nu_js Ry; //
+ cc_trigger Tl; //
+ cc_trigger Tr; //
+};
+
+#pragma pack(pop)
+
+#endif //WIIMOTE_HID_H
diff --git a/Source/Plugins/Plugin_Wiimote-testing/Src/wiimote_real.cpp b/Source/Plugins/Plugin_Wiimote-testing/Src/wiimote_real.cpp
new file mode 100644
index 0000000000..5396abd379
--- /dev/null
+++ b/Source/Plugins/Plugin_Wiimote-testing/Src/wiimote_real.cpp
@@ -0,0 +1,490 @@
+// Copyright (C) 2003-2008 Dolphin Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official SVN repository and contact information can be found at
+// http://code.google.com/p/dolphin-emu/
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Includes
+// ŻŻŻŻŻŻŻŻŻŻŻŻŻ
+#include // System
+#include
+
+#include "wiiuse.h"
+
+#include "Common.h"
+#include "Thread.h"
+#include "StringUtil.h"
+#include "Timer.h"
+#include "pluginspecs_wiimote.h"
+
+#include "wiimote_hid.h"
+#include "main.h"
+#include "Config.h"
+#include "EmuMain.h"
+#include "EmuDefinitions.h"
+#define EXCLUDE_H // Avoid certain declarations in wiimote_real.h
+#include "wiimote_real.h"
+#if defined(HAVE_WX) && HAVE_WX
+ #include "ConfigDlg.h"
+#endif
+
+extern SWiimoteInitialize g_WiimoteInitialize;
+////////////////////////////////////////
+
+
+namespace WiiMoteReal
+{
+
+//******************************************************************************
+// Forwarding
+//******************************************************************************
+
+class CWiiMote;
+
+#ifdef _WIN32
+ DWORD WINAPI ReadWiimote_ThreadFunc(void* arg);
+#else
+ void* ReadWiimote_ThreadFunc(void* arg);
+#endif
+//******************************************************************************
+// Variable declarations
+//******************************************************************************
+
+wiimote_t** g_WiiMotesFromWiiUse = NULL;
+Common::Thread* g_pReadThread = NULL;
+int g_NumberOfWiiMotes;
+CWiiMote* g_WiiMotes[MAX_WIIMOTES];
+bool g_Shutdown = false;
+bool g_ThreadGoing = false;
+bool g_LocalThread = true;
+bool g_IRSensing = false;
+bool g_MotionSensing = false;
+u64 g_UpdateTime = 0;
+int g_UpdateCounter = 0;
+bool g_RunTemporary = false;
+int g_RunTemporaryCountdown = 0;
+u8 g_EventBuffer[32];
+
+//******************************************************************************
+// Probably this class should be in its own file
+//******************************************************************************
+
+class CWiiMote
+{
+public:
+
+//////////////////////////////////////////
+// On create and on uncreate
+// ---------------
+CWiiMote(u8 _WiimoteNumber, wiimote_t* _pWiimote)
+ : m_WiimoteNumber(_WiimoteNumber)
+ , m_channelID(0)
+ , m_pWiiMote(_pWiimote)
+ , m_pCriticalSection(NULL)
+ , m_LastReportValid(false)
+{
+ m_pCriticalSection = new Common::CriticalSection();
+
+ //wiiuse_set_leds(m_pWiiMote, WIIMOTE_LED_4);
+
+ #ifdef _WIN32
+ // F|RES: i dunno if we really need this
+ CancelIo(m_pWiiMote->dev_handle);
+ #endif
+}
+
+virtual ~CWiiMote()
+{
+ delete m_pCriticalSection;
+};
+//////////////////////
+
+
+//////////////////////////////////////////
+// Queue raw HID data from the core to the wiimote
+// ---------------
+void SendData(u16 _channelID, const u8* _pData, u32 _Size)
+{
+ m_channelID = _channelID;
+
+ m_pCriticalSection->Enter();
+ {
+ SEvent WriteEvent;
+ memcpy(WriteEvent.m_PayLoad, _pData + 1, _Size - 1);
+ m_EventWriteQueue.push(WriteEvent);
+
+ // Debugging
+ //std::string Temp = ArrayToString(WriteEvent.m_PayLoad, 28, 0, 30);
+ //INFO_LOG(CONSOLE, "Wiimote Write:\n%s\n", Temp.c_str());
+ }
+ m_pCriticalSection->Leave();
+}
+/////////////////////
+
+
+//////////////////////////////////////////////////
+/* Read and write data to the Wiimote */
+// ---------------
+void ReadData()
+{
+ m_pCriticalSection->Enter();
+
+ // Send data to the Wiimote
+ if (!m_EventWriteQueue.empty())
+ {
+ //INFO_LOG(CONSOLE, "Writing data to the Wiimote\n");
+ SEvent& rEvent = m_EventWriteQueue.front();
+ wiiuse_io_write(m_pWiiMote, (byte*)rEvent.m_PayLoad, MAX_PAYLOAD);
+ m_EventWriteQueue.pop();
+
+#ifdef _WIN32
+ // Debugging. Move the data one step to the right first.
+ memcpy(rEvent.m_PayLoad + 1, rEvent.m_PayLoad, sizeof(rEvent.m_PayLoad) - 1);
+ rEvent.m_PayLoad[0] = 0xa2;
+ InterruptDebugging(false, rEvent.m_PayLoad);
+#endif
+ }
+
+ m_pCriticalSection->Leave();
+
+ // Read data from wiimote (but don't send it to the core, just filter and queue)
+ if (wiiuse_io_read(m_pWiiMote))
+ {
+ const byte* pBuffer = m_pWiiMote->event_buf;
+ #ifndef _WIN32
+ // The Linux packets are starting out one spot before the Windows one. This should really be handled in the wiiuse library
+ pBuffer++;
+ #endif
+ // Check if we have a channel (connection) if so save the data...
+ if (m_channelID > 0)
+ {
+ m_pCriticalSection->Enter();
+
+ // Filter out data reports
+ if (pBuffer[0] >= 0x30)
+ {
+ // Copy Buffer to LastReport
+ memcpy(m_LastReport.m_PayLoad, pBuffer, MAX_PAYLOAD);
+ m_LastReportValid = true;
+ }
+ else
+ {
+ // Copy Buffer to ImportantEvent
+ SEvent ImportantEvent;
+ memcpy(ImportantEvent.m_PayLoad, pBuffer, MAX_PAYLOAD);
+
+ // Put it in the read queue right away
+ m_EventReadQueue.push(ImportantEvent);
+ }
+ m_pCriticalSection->Leave();
+ }
+ }
+};
+/////////////////////
+
+
+//////////////////////////////////////////
+// Send queued data to the core
+// ---------------
+void Update()
+{
+ // Thread function
+ m_pCriticalSection->Enter();
+
+ if (m_EventReadQueue.empty())
+ {
+ // Send the data report
+ if (m_LastReportValid) SendEvent(m_LastReport);
+ }
+ else
+ {
+ // Send a 0x20, 0x21 or 0x22 report
+ SendEvent(m_EventReadQueue.front());
+ m_EventReadQueue.pop();
+ }
+
+ m_pCriticalSection->Leave();
+};
+/////////////////////
+
+
+//////////////////////////////////////////
+// Clear events
+// ---------------
+void ClearEvents()
+{
+ while (!m_EventReadQueue.empty())
+ m_EventReadQueue.pop();
+ while (!m_EventWriteQueue.empty())
+ m_EventWriteQueue.pop();
+}
+/////////////////////
+
+private:
+
+ struct SEvent
+ {
+ SEvent()
+ {
+ memset(m_PayLoad, 0, MAX_PAYLOAD);
+ }
+ byte m_PayLoad[MAX_PAYLOAD];
+ };
+ typedef std::queue CEventQueue;
+
+ u8 m_WiimoteNumber; // Just for debugging
+ u16 m_channelID;
+ CEventQueue m_EventReadQueue; // Read from Wiimote
+ CEventQueue m_EventWriteQueue; // Write to Wiimote
+ Common::CriticalSection* m_pCriticalSection;
+ bool m_LastReportValid;
+ SEvent m_LastReport;
+ wiimote_t* m_pWiiMote; // This is g_WiiMotesFromWiiUse[]
+
+//////////////////////////////////////////
+// Send queued data to the core
+// ---------------
+void SendEvent(SEvent& _rEvent)
+{
+ // We don't have an answer channel
+ if (m_channelID == 0) return;
+
+ // Check event buffer
+ u8 Buffer[1024];
+ u32 Offset = 0;
+ hid_packet* pHidHeader = (hid_packet*)(Buffer + Offset);
+ Offset += sizeof(hid_packet);
+ pHidHeader->type = HID_TYPE_DATA;
+ pHidHeader->param = HID_PARAM_INPUT;
+
+ // Create the buffer
+ memcpy(&Buffer[Offset], _rEvent.m_PayLoad, MAX_PAYLOAD);
+ /* This Offset value is not exactly correct like it is for the emulated Wiimote reports. It's
+ often to big, but I guess that's okay. The game will know how big the actual data is. */
+ Offset += MAX_PAYLOAD;
+
+ // Send it
+ g_WiimoteInitialize.pWiimoteInput(m_channelID, Buffer, Offset);
+
+ // Debugging
+ // ReadDebugging(false, Buffer, Offset);
+}
+/////////////////////
+};
+
+
+
+//******************************************************************************
+// Function Definitions
+//******************************************************************************
+
+void SendAcc(u8 _ReportID)
+{
+ byte DataAcc[MAX_PAYLOAD];
+
+ DataAcc[0] = 0x22; // Report 0x12
+ DataAcc[1] = 0x00; // Core buttons
+ DataAcc[2] = 0x00;
+ DataAcc[3] = _ReportID; // Reporting mode
+
+ // TODO: Update for multiple wiimotes?
+ wiiuse_io_write(WiiMoteReal::g_WiiMotesFromWiiUse[0], (byte*)DataAcc, MAX_PAYLOAD);
+
+ std::string Temp = ArrayToString(DataAcc, 28, 0, 30);
+ INFO_LOG(CONSOLE, "SendAcc: %s\n", Temp.c_str());
+
+ //22 00 00 _reportID 00
+}
+
+// Clear any potential queued events
+void ClearEvents()
+{
+ for (int i = 0; i < g_NumberOfWiiMotes; i++)
+ g_WiiMotes[i]->ClearEvents();
+}
+
+// Flash lights, and if connecting, also rumble
+void FlashLights(bool Connect)
+{
+
+ for (int i = 0; i < g_NumberOfWiiMotes; i++)
+ {
+ if(Connect) wiiuse_rumble(WiiMoteReal::g_WiiMotesFromWiiUse[i], 1);
+ wiiuse_set_leds(WiiMoteReal::g_WiiMotesFromWiiUse[i], WIIMOTE_LED_1 | WIIMOTE_LED_2 | WIIMOTE_LED_3 | WIIMOTE_LED_4);
+ }
+ sleep(100);
+
+ for (int i = 0; i < g_NumberOfWiiMotes; i++)
+ {
+ if(Connect)
+ {
+ wiiuse_rumble(WiiMoteReal::g_WiiMotesFromWiiUse[i], 0);
+
+ // End with light 1 or 4
+ wiiuse_set_leds(WiiMoteReal::g_WiiMotesFromWiiUse[i], WIIMOTE_LED_1);
+ }
+ else wiiuse_set_leds(WiiMoteReal::g_WiiMotesFromWiiUse[i], WIIMOTE_LED_4);
+ }
+}
+
+int Initialize()
+{
+ // Return if already initialized
+ if (g_RealWiiMoteInitialized) return g_NumberOfWiiMotes;
+
+ // Clear the wiimote classes
+ memset(g_WiiMotes, 0, sizeof(CWiiMote*) * MAX_WIIMOTES);
+
+ // Call Wiiuse.dll
+ g_WiiMotesFromWiiUse = wiiuse_init(MAX_WIIMOTES);
+ g_NumberOfWiiMotes = wiiuse_find(g_WiiMotesFromWiiUse, MAX_WIIMOTES, 5);
+ if (g_NumberOfWiiMotes > 0) g_RealWiiMotePresent = true;
+ INFO_LOG(CONSOLE, "Found No of Wiimotes: %i\n", g_NumberOfWiiMotes);
+
+ for (int i = 0; i < g_NumberOfWiiMotes; i++)
+ {
+ // Remove the wiiuse_poll() threshold
+ wiiuse_set_accel_threshold(g_WiiMotesFromWiiUse[i], 0);
+
+ // Set the sensor bar position, this should only affect the internal wiiuse api functions
+ wiiuse_set_ir_position(g_WiiMotesFromWiiUse[i], WIIUSE_IR_ABOVE);
+
+ // Set flags
+ //wiiuse_set_flags(g_WiiMotesFromWiiUse[i], NULL, WIIUSE_SMOOTHING);
+ }
+ // I don't seem to need wiiuse_connect() in Windows. But Linux needs it.
+ #ifndef _WIN32
+ int Connect = wiiuse_connect(g_WiiMotesFromWiiUse, MAX_WIIMOTES);
+ INFO_LOG(CONSOLE, "Connected: %i\n", Connect);
+ #endif
+
+ // If we are connecting from the config window without a game running we flash the lights
+ if (!g_EmulatorRunning && g_RealWiiMotePresent) FlashLights(true);
+
+ // Create Wiimote classes
+ for (int i = 0; i < g_NumberOfWiiMotes; i++)
+ g_WiiMotes[i] = new CWiiMote(i + 1, g_WiiMotesFromWiiUse[i]);
+
+ // Create a new thread and start listening for Wiimote data
+ if (g_NumberOfWiiMotes > 0)
+ g_pReadThread = new Common::Thread(ReadWiimote_ThreadFunc, NULL);
+
+ // If we are not using the emulated wiimote we can run the thread temporary until the data has beeen copied
+ if(g_Config.bUseRealWiimote) g_RunTemporary = true;
+
+ /* Allocate memory and copy the Wiimote eeprom accelerometer neutral values to g_Eeprom. Unlike with
+ and extension we have to do this here, because this data is only read once when the Wiimote
+ is connected. Also, we can't change the neutral values the wiimote will report, I think, unless
+ we update its eeprom? In any case it's probably better to let the current calibration be where it
+ is and adjust the global values after that to avoid overwriting critical data on any Wiimote. */
+ // TODO: Update for multiple wiimotes?
+ byte *data = (byte*)malloc(sizeof(byte) * sizeof(WiiMoteEmu::EepromData_0));
+ wiiuse_read_data(g_WiiMotesFromWiiUse[0], data, 0, sizeof(WiiMoteEmu::EepromData_0));
+
+ // Don't run the Wiimote thread if no wiimotes were found
+ if (g_NumberOfWiiMotes > 0) g_Shutdown = false;
+
+ // Initialized, even if we didn't find a Wiimote
+ g_RealWiiMoteInitialized = true;
+
+ return g_NumberOfWiiMotes;
+}
+
+void DoState(void* ptr, int mode) {}
+
+void Shutdown(void)
+{
+ // Stop the loop in the thread
+ g_Shutdown = true;
+
+ // Stop the thread
+ if (g_pReadThread != NULL)
+ {
+ delete g_pReadThread;
+ g_pReadThread = NULL;
+ }
+
+ // Delete the wiimotes
+ for (int i = 0; i < g_NumberOfWiiMotes; i++)
+ {
+ delete g_WiiMotes[i];
+ g_WiiMotes[i] = NULL;
+ }
+
+ // Flash flights
+ if (!g_EmulatorRunning && g_RealWiiMotePresent)
+ FlashLights(false);
+
+ // Clean up wiiuse
+ wiiuse_cleanup(g_WiiMotesFromWiiUse, g_NumberOfWiiMotes);
+
+ // Uninitialized
+ g_RealWiiMoteInitialized = false;
+ g_RealWiiMotePresent = false;
+}
+
+void InterruptChannel(u16 _channelID, const void* _pData, u32 _Size)
+{
+ //INFO_LOG(CONSOLE, "Real InterruptChannel\n");
+ // TODO: Update for multiple Wiimotes
+ g_WiiMotes[0]->SendData(_channelID, (const u8*)_pData, _Size);
+}
+
+void ControlChannel(u16 _channelID, const void* _pData, u32 _Size)
+{
+ //INFO_LOG(CONSOLE, "Real ControlChannel\n");
+ g_WiiMotes[0]->SendData(_channelID, (const u8*)_pData, _Size);
+}
+
+
+//////////////////////////////////
+// Read the Wiimote once
+// ---------------
+void Update()
+{
+ //INFO_LOG(CONSOLE, "Real Update\n");
+ for (int i = 0; i < g_NumberOfWiiMotes; i++)
+ {
+ g_WiiMotes[i]->Update();
+ }
+}
+
+//////////////////////////////////
+/* Continuously read the Wiimote status. However, the actual sending of data occurs in Update(). If we are
+ not currently using the real Wiimote we allow the separate ReadWiimote() function to run. Wo don't use
+ them at the same time to avoid a potential collision. */
+// ---------------
+#ifdef _WIN32
+ DWORD WINAPI ReadWiimote_ThreadFunc(void* arg)
+#else
+ void *ReadWiimote_ThreadFunc(void* arg)
+#endif
+{
+ while (!g_Shutdown)
+ {
+ // We need g_ThreadGoing to do a manual WaitForSingleObject() from the configuration window
+ g_ThreadGoing = true;
+ if(g_Config.bUseRealWiimote && !g_RunTemporary)
+ for (int i = 0; i < g_NumberOfWiiMotes; i++) g_WiiMotes[i]->ReadData();
+ else
+ ReadWiimote();
+ g_ThreadGoing = false;
+ }
+ return 0;
+}
+
+}; // end of namespace
+
diff --git a/Source/Plugins/Plugin_Wiimote-testing/Src/wiimote_real.h b/Source/Plugins/Plugin_Wiimote-testing/Src/wiimote_real.h
new file mode 100644
index 0000000000..109711b895
--- /dev/null
+++ b/Source/Plugins/Plugin_Wiimote-testing/Src/wiimote_real.h
@@ -0,0 +1,67 @@
+// Copyright (C) 2003-2008 Dolphin Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official SVN repository and contact information can be found at
+// http://code.google.com/p/dolphin-emu/
+
+
+#ifndef WIIMOTE_REAL_H
+#define WIIMOTE_REAL_H
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Includes
+// ŻŻŻŻŻŻŻŻŻŻŻŻŻ
+#include "wiiuse.h"
+///////////////////////////////////
+
+
+namespace WiiMoteReal
+{
+
+#define MAX_WIIMOTES 1
+
+int Initialize();
+void DoState(void* ptr, int mode);
+void Shutdown(void);
+void InterruptChannel(u16 _channelID, const void* _pData, u32 _Size);
+void ControlChannel(u16 _channelID, const void* _pData, u32 _Size);
+void Update();
+
+void SendAcc(u8 _ReportID);
+void SetDataReportingMode(u8 ReportingMode = 0);
+void ClearEvents();
+
+// The alternative Wiimote loop
+void ReadWiimote();
+bool IRDataOK(struct wiimote_t* wm);
+
+#ifndef EXCLUDE_H
+ extern wiimote_t** g_WiiMotesFromWiiUse;
+ extern bool g_Shutdown;
+ extern bool g_ThreadGoing;
+ extern int g_NumberOfWiiMotes;
+ extern bool g_MotionSensing;
+ extern bool g_IRSensing;
+ extern u64 g_UpdateTime;
+ extern int g_UpdateCounter;
+ extern bool g_RunTemporary;
+ extern int g_RunTemporaryCountdown;
+ extern u8 g_EventBuffer[32];
+#endif
+
+}; // WiiMoteReal
+
+#endif
+