Wiimote: Partial work on movement recording (not working yet)

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@2021 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
John Peterson 2009-01-28 16:09:08 +00:00
parent 7bc798b7f1
commit 946fb12752
13 changed files with 903 additions and 325 deletions

View File

@ -16,6 +16,9 @@
// http://code.google.com/p/dolphin-emu/
// see IniFile.h
//////////////////////////////////////////////////////////////////////////////////////
// Include
// ------------
#include <stdlib.h>
#include <stdio.h>
@ -27,15 +30,24 @@
#include "StringUtil.h"
#include "IniFile.h"
///////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////
// Class
// ------------
IniFile::IniFile()
{}
IniFile::~IniFile()
{}
///////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////
// Section functions used locally only
// ------------
Section::Section()
: lines(), name(""), comment("") {}
@ -79,6 +91,7 @@ Section* IniFile::GetOrCreateSection(const char* sectionName)
return(section);
}
///////////////////////////////
bool IniFile::DeleteSection(const char* sectionName)
@ -158,7 +171,194 @@ std::string* IniFile::GetLine(Section* section, const char* key, std::string* va
return 0;
}
void IniFile::SetLines(const char* sectionName, const std::vector<std::string> &lines)
{
Section* section = GetOrCreateSection(sectionName);
section->lines.clear();
for (std::vector<std::string>::const_iterator iter = lines.begin(); iter != lines.end(); ++iter)
{
section->lines.push_back(*iter);
}
}
bool IniFile::DeleteKey(const char* sectionName, const char* key)
{
Section* section = GetSection(sectionName);
if (!section)
{
return false;
}
std::string* line = GetLine(section, key, 0, 0);
for (std::vector<std::string>::iterator liter = section->lines.begin(); liter != section->lines.end(); ++liter)
{
if (line == &(*liter))
{
section->lines.erase(liter);
return true;
}
}
return false; //shouldn't happen
}
bool IniFile::GetKeys(const char* sectionName, std::vector<std::string>& keys) const
{
const Section* section = GetSection(sectionName);
if (!section)
{
return false;
}
keys.clear();
for (std::vector<std::string>::const_iterator liter = section->lines.begin(); liter != section->lines.end(); ++liter)
{
std::string key;
ParseLine(*liter, &key, 0, 0);
keys.push_back(key);
}
return true;
}
bool IniFile::GetLines(const char* sectionName, std::vector<std::string>& lines) const
{
const Section* section = GetSection(sectionName);
if (!section)
return false;
lines.clear();
for (std::vector<std::string>::const_iterator iter = section->lines.begin(); iter != section->lines.end(); ++iter)
{
std::string line = StripSpaces(*iter);
int commentPos = (int)line.find('#');
if (commentPos == 0)
{
continue;
}
if (commentPos != (int)std::string::npos)
{
line = StripSpaces(line.substr(0, commentPos));
}
lines.push_back(line);
}
return true;
}
void IniFile::SortSections()
{
std::sort(sections.begin(), sections.end());
}
//////////////////////////////////////////////////////////////////////////////////////
// Load and save file
// ------------
bool IniFile::Load(const char* filename)
{
// Maximum number of letters in a line
static const int MAX_BYTES = 1024*10;
sections.clear();
sections.push_back(Section(""));
//first section consists of the comments before the first real section
// Open file
std::ifstream in;
in.open(filename, std::ios::in);
if (in.fail())
{
return false;
}
while (!in.eof())
{
char templine[MAX_BYTES];
in.getline(templine, MAX_BYTES);
std::string line = templine;
if (in.eof())
{
break;
}
if (line.size() > 0)
{
if (line[0] == '[')
{
size_t endpos = line.find("]");
if (endpos != std::string::npos)
{
// New section!
std::string sub = line.substr(1, endpos - 1);
sections.push_back(Section(sub));
if (endpos + 1 < line.size())
{
sections[sections.size() - 1].comment = line.substr(endpos + 1);
}
}
}
else
{
sections[sections.size() - 1].lines.push_back(line);
}
}
}
in.close();
return true;
}
bool IniFile::Save(const char* filename)
{
std::ofstream out;
out.open(filename, std::ios::out);
if (out.fail())
{
return false;
}
for (std::vector<Section>::const_iterator iter = sections.begin(); iter != sections.end(); ++iter)
{
const Section& section = *iter;
if (section.name != "")
{
out << "[" << section.name << "]" << section.comment << std::endl;
}
for (std::vector<std::string>::const_iterator liter = section.lines.begin(); liter != section.lines.end(); ++liter)
{
std::string s = *liter;
out << s << std::endl;
}
}
out.close();
return true;
}
//////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////
// Get and set elements
// ------------
void IniFile::Set(const char* sectionName, const char* key, const char* newValue)
{
Section* section = GetOrCreateSection(sectionName);
@ -195,17 +395,6 @@ void IniFile::Set(const char* sectionName, const char* key, bool newValue)
Set(sectionName, key, StringFromBool(newValue).c_str());
}
void IniFile::SetLines(const char* sectionName, const std::vector<std::string> &lines)
{
Section* section = GetOrCreateSection(sectionName);
section->lines.clear();
for (std::vector<std::string>::const_iterator iter = lines.begin(); iter != lines.end(); ++iter)
{
section->lines.push_back(*iter);
}
}
bool IniFile::Get(const char* sectionName, const char* key, std::string* value, const char* defaultValue)
{
Section* section = GetSection(sectionName);
@ -279,173 +468,9 @@ bool IniFile::Get(const char* sectionName, const char* key, bool* value, bool de
*value = defaultValue;
return false;
}
////////////////////////////////////////
bool IniFile::DeleteKey(const char* sectionName, const char* key)
{
Section* section = GetSection(sectionName);
if (!section)
{
return false;
}
std::string* line = GetLine(section, key, 0, 0);
for (std::vector<std::string>::iterator liter = section->lines.begin(); liter != section->lines.end(); ++liter)
{
if (line == &(*liter))
{
section->lines.erase(liter);
return true;
}
}
return false; //shouldn't happen
}
bool IniFile::Load(const char* filename)
{
sections.clear();
sections.push_back(Section(""));
//first section consists of the comments before the first real section
std::ifstream in;
in.open(filename, std::ios::in);
if (in.fail())
{
return false;
}
while (!in.eof())
{
char templine[512];
in.getline(templine, 512);
std::string line = templine;
if (in.eof())
{
break;
}
if (line.size() > 0)
{
if (line[0] == '[')
{
size_t endpos = line.find("]");
if (endpos != std::string::npos)
{
// New section!
std::string sub = line.substr(1, endpos - 1);
sections.push_back(Section(sub));
if (endpos + 1 < line.size())
{
sections[sections.size() - 1].comment = line.substr(endpos + 1);
}
}
}
else
{
sections[sections.size() - 1].lines.push_back(line);
}
}
}
in.close();
return true;
}
bool IniFile::Save(const char* filename)
{
std::ofstream out;
out.open(filename, std::ios::out);
if (out.fail())
{
return false;
}
for (std::vector<Section>::const_iterator iter = sections.begin(); iter != sections.end(); ++iter)
{
const Section& section = *iter;
if (section.name != "")
{
out << "[" << section.name << "]" << section.comment << std::endl;
}
for (std::vector<std::string>::const_iterator liter = section.lines.begin(); liter != section.lines.end(); ++liter)
{
std::string s = *liter;
out << s << std::endl;
}
}
out.close();
return true;
}
bool IniFile::GetKeys(const char* sectionName, std::vector<std::string>& keys) const
{
const Section* section = GetSection(sectionName);
if (!section)
{
return false;
}
keys.clear();
for (std::vector<std::string>::const_iterator liter = section->lines.begin(); liter != section->lines.end(); ++liter)
{
std::string key;
ParseLine(*liter, &key, 0, 0);
keys.push_back(key);
}
return true;
}
bool IniFile::GetLines(const char* sectionName, std::vector<std::string>& lines) const
{
const Section* section = GetSection(sectionName);
if (!section)
return false;
lines.clear();
for (std::vector<std::string>::const_iterator iter = section->lines.begin(); iter != section->lines.end(); ++iter)
{
std::string line = StripSpaces(*iter);
int commentPos = (int)line.find('#');
if (commentPos == 0)
{
continue;
}
if (commentPos != (int)std::string::npos)
{
line = StripSpaces(line.substr(0, commentPos));
}
lines.push_back(line);
}
return true;
}
void IniFile::SortSections()
{
std::sort(sections.begin(), sections.end());
}
/*
int main()

View File

@ -233,7 +233,7 @@
<Tool
Name="VCLinkerTool"
AdditionalOptions="/NODEFAULTLIB:msvcrt.lib"
AdditionalDependencies="comctl32.lib wiiuse.lib"
AdditionalDependencies="comctl32.lib winmm.lib wiiuse.lib"
OutputFile="..\..\..\Binary\Win32\Plugins\Plugin_Wiimote.dll"
LinkIncremental="1"
AdditionalLibraryDirectories="..\..\..\Externals\WiiUse\win32"

View File

@ -42,6 +42,7 @@ void Config::Load()
iniFile.Get("Real", "Connect", &bConnectRealWiimote, true);
iniFile.Get("Real", "Use", &bUseRealWiimote, true);
iniFile.Get("Real", "UpdateStatus", &bUpdateRealWiimote, true);
}
void Config::Save()
@ -54,7 +55,8 @@ void Config::Save()
iniFile.Set("Settings", "ClassicControllerConnected", bClassicControllerConnected);
iniFile.Set("Real", "Connect", bConnectRealWiimote);
iniFile.Set("Real", "Use", bUseRealWiimote);
iniFile.Set("Real", "Use", bUseRealWiimote);
iniFile.Set("Real", "UpdateStatus", bUpdateRealWiimote);
iniFile.Save(FULL_CONFIG_DIR "Wiimote.ini");
}

View File

@ -36,7 +36,7 @@ struct Config
bool bNunchuckConnected, bClassicControllerConnected;
// Real Wiimote
bool bConnectRealWiimote, bUseRealWiimote;
bool bConnectRealWiimote, bUseRealWiimote, bUpdateRealWiimote;
};
extern Config g_Config;

View File

@ -20,11 +20,15 @@
// Include
// ------------
//#include "Common.h" // for u16
#include "CommonTypes.h" // for u16
#include "IniFile.h"
#include "Timer.h"
#include "wiimote_real.h" // Local
#include "main.h"
#include "ConfigDlg.h"
#include "Config.h"
#include "EmuSubroutines.h" // for WmRequestStatus
#include "main.h"
#include "wiimote_real.h"
/////////////////////////////
@ -48,13 +52,33 @@ BEGIN_EVENT_TABLE(ConfigDialog,wxDialog)
EVT_CHECKBOX(ID_CONNECT_REAL, ConfigDialog::GeneralSettingsChanged)
EVT_CHECKBOX(ID_USE_REAL, ConfigDialog::GeneralSettingsChanged)
EVT_CHECKBOX(ID_UPDATE_REAL, 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)
EVT_TIMER(IDTM_EXIT, ConfigDialog::FlashLights)
//EVT_TIMER(IDTM_UPDATE, ConfigDialog::Update)
EVT_TIMER(IDTM_UPDATE, ConfigDialog::Update)
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)
@ -63,19 +87,138 @@ ConfigDialog::ConfigDialog(wxWindow *parent, wxWindowID id, const wxString &titl
m_ExitTimer = new wxTimer(this, IDTM_EXIT);
// Reset values
ShutDown = false;
m_TimeoutTimer = new wxTimer(this, IDTM_UPDATE);
m_TimeoutATimer = new wxTimer(this, IDTM_UPDATEA);
// Reset values
m_bWaitForRecording = false;
m_bRecording = false;
#endif
ControlsCreated = false;
m_vRecording.resize(RECORDING_ROWS + 1);
g_Config.Load();
CreateGUIControls();
LoadFile();
UpdateGUI();
wxTheApp->Connect(wxID_ANY, wxEVT_KEY_DOWN, // Keyboard
wxKeyEventHandler(ConfigDialog::OnKeyDown),
(wxObject*)0, this);
}
ConfigDialog::~ConfigDialog()
{
g_FrameOpen = false;
if (!g_EmulatorRunning) Shutdown();
{
}
void ConfigDialog::OnKeyDown(wxKeyEvent& event)
{
event.Skip();
// Escape a recording event
if (event.GetKeyCode() == WXK_ESCAPE)
{
m_bWaitForRecording = false;
m_bRecording = false;
UpdateGUI();
}
}
void ConfigDialog::OnClose(wxCloseEvent& WXUNUSED (event))
{
SaveFile();
g_Config.Save();
g_FrameOpen = false;
SuccessAlert("Saved\n");
if (!g_EmulatorRunning) Shutdown();
EndModal(0);
}
void ConfigDialog::CloseClick(wxCommandEvent& WXUNUSED (event))
{
// wxWidgets function. This will also trigger EVT_CLOSE().
Close();
}
void ConfigDialog::AboutClick(wxCommandEvent& WXUNUSED (event))
{
}
void ConfigDialog::LoadFile()
{
Console::Print("LoadFile\n");
IniFile file;
file.Load("WiimoteMovement.ini");
for(int i = 1; i < (RECORDING_ROWS + 1); i++)
{
// Get row name
std::string SaveName = StringFromFormat("Recording%i", i);
// HotKey
int TmpRecordHotKey; file.Get(SaveName.c_str(), "HotKey", &TmpRecordHotKey, -1);
m_RecordHotKey[i]->SetSelection(TmpRecordHotKey);
// Movement name
std::string TmpMovementName; file.Get(SaveName.c_str(), "MovementName", &TmpMovementName, "");
m_RecordText[i]->SetValue(TmpMovementName.c_str());
// Game name
std::string TmpGameName; file.Get(SaveName.c_str(), "GameName", &TmpGameName, "");
m_RecordGameText[i]->SetValue(TmpGameName.c_str());
// Recording speed
int TmpRecordSpeed; file.Get(SaveName.c_str(), "RecordingSpeed", &TmpRecordSpeed, -1);
if(TmpRecordSpeed != -1)
m_RecordSpeed[i]->SetValue(wxString::Format(wxT("%i"), TmpRecordSpeed));
else
m_RecordSpeed[i]->SetValue(wxT(""));
// Playback speed (currently always saved directly after a recording)
int TmpPlaybackSpeed; file.Get(SaveName.c_str(), "PlaybackSpeed", &TmpPlaybackSpeed, -1);
m_RecordPlayBackSpeed[i]->SetSelection(TmpPlaybackSpeed);
}
}
void ConfigDialog::SaveFile()
{
Console::Print("SaveFile\n");
IniFile file;
file.Load("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(), "HotKey", m_RecordHotKey[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("WiimoteMovement.ini");
}
/////////////////////////////
/////////////////////////////////////////////////////////////////////////
// Create GUI
@ -142,7 +285,7 @@ void ConfigDialog::CreateGUIControls()
////////////////////////////////////////////////////////////////////////////////
// Real Wiimote
// ----------------
// General
// Basic Settings
wxStaticBoxSizer * sbRealBasic = new wxStaticBoxSizer(wxVERTICAL, m_PageReal, wxT("Basic Settings"));
m_ConnectRealWiimote = new wxCheckBox(m_PageReal, ID_CONNECT_REAL, wxT("Connect real Wiimote"));
m_UseRealWiimote = new wxCheckBox(m_PageReal, ID_USE_REAL, wxT("Use real Wiimote"));
@ -151,10 +294,25 @@ void ConfigDialog::CreateGUIControls()
m_ConnectRealWiimote->SetValue(g_Config.bConnectRealWiimote);
m_UseRealWiimote->SetValue(g_Config.bUseRealWiimote);
// ==================================================
// Status
wxStaticBoxSizer * sbRealStatus = new wxStaticBoxSizer(wxVERTICAL, m_PageReal, wxT("Status"));
m_TextUpdateRate = new wxStaticText(m_PageReal, wxID_ANY, wxT("Update rate: 000 times/s"));
m_UpdateMeters = new wxCheckBox(m_PageReal, 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 unnecessary slowdown that comes from redrawing the\n"
"configuration screen. Remember that you also need to press '+' on your Wiimote before you can record movements."
));
sbRealStatus->Add(m_TextUpdateRate, 0, wxEXPAND | (wxALL), 5);
sbRealStatus->Add(m_UpdateMeters, 0, wxEXPAND | (wxLEFT | wxRIGHT | wxUP), 5);
// ==================================================
// Wiimote Status
// ----------------
wxBoxSizer * sbRealStatus = new wxBoxSizer(wxHORIZONTAL);
wxBoxSizer * sbRealWiimoteStatus = new wxBoxSizer(wxHORIZONTAL);
wxStaticBoxSizer * sbRealBattery = new wxStaticBoxSizer(wxVERTICAL, m_PageReal, wxT("Battery"));
wxStaticBoxSizer * sbRealRoll = new wxStaticBoxSizer(wxHORIZONTAL, m_PageReal, wxT("Roll and Pitch"));
@ -213,10 +371,10 @@ void ConfigDialog::CreateGUIControls()
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);
sbRealStatus->Add(sbRealBattery, 0, wxEXPAND | (wxALL), 5);
sbRealStatus->Add(sbRealRoll, 0, wxEXPAND | (wxALL), 5);
sbRealStatus->Add(sbRealGForce, 0, wxEXPAND | (wxALL), 5);
sbRealStatus->Add(sbRealAccel, 0, wxEXPAND | (wxALL), 5);
sbRealWiimoteStatus->Add(sbRealBattery, 0, wxEXPAND | (wxLEFT), 0);
sbRealWiimoteStatus->Add(sbRealRoll, 0, wxEXPAND | (wxLEFT), 5);
sbRealWiimoteStatus->Add(sbRealGForce, 0, wxEXPAND | (wxLEFT), 5);
sbRealWiimoteStatus->Add(sbRealAccel, 0, wxEXPAND | (wxLEFT), 5);
m_GaugeBattery->SetToolTip(wxT("Press '+' to show the current status. Press '-' to stop recording the status."));
// ==========================================
@ -228,28 +386,35 @@ void ConfigDialog::CreateGUIControls()
wxStaticBoxSizer * sbRealRecord = new wxStaticBoxSizer(wxVERTICAL, m_PageReal, wxT("Record movements"));
wxArrayString StrHotKey;
for(int i = 0; i < 10; i++)
StrHotKey.Add(wxString::Format(wxT("Shift + %i"), i));
for(int i = 0; i < 10; i++) StrHotKey.Add(wxString::Format(wxT("%i"), i));
wxArrayString StrPlayBackSpeed;
for(int i = 1; i < 8; i++)
StrPlayBackSpeed.Add(wxString::Format(wxT("%i"), i*5));
for(int i = 1; i < 15; i++) StrPlayBackSpeed.Add(wxString::Format(wxT("%i"), i*25));
wxBoxSizer * sRealRecord[RECORDING_ROWS];
wxBoxSizer * sRealRecord[RECORDING_ROWS + 1];
wxStaticText * m_TextRec = new wxStaticText(m_PageReal, wxID_ANY, wxT("Rec."), wxDefaultPosition, wxSize(25, 15), wxALIGN_CENTRE);
wxStaticText * m_TextHotKey = new wxStaticText(m_PageReal, wxID_ANY, wxT("HotKey"), wxDefaultPosition, wxSize(62, 15), wxALIGN_CENTRE);
wxStaticText * m_TextMovement = new wxStaticText(m_PageReal, wxID_ANY, wxT("Movement name"), wxDefaultPosition, wxSize(262, 15), wxALIGN_CENTRE);
wxStaticText * m_TextGame = new wxStaticText(m_PageReal, wxID_ANY, wxT("Game name"), wxDefaultPosition, wxSize(262, 15), wxALIGN_CENTRE);
wxStaticText * m_TextRecSped = new wxStaticText(m_PageReal, wxID_ANY, wxT("R. s."), wxDefaultPosition, wxSize(35, 15), wxALIGN_CENTRE);
wxStaticText * m_TextRec = new wxStaticText(m_PageReal, wxID_ANY, wxT("Rec."), wxDefaultPosition, wxSize(80, 15), wxALIGN_CENTRE);
wxStaticText * m_TextHotKey = new wxStaticText(m_PageReal, wxID_ANY, wxT("HotKey"), wxDefaultPosition, wxSize(40, 15), wxALIGN_CENTRE);
wxStaticText * m_TextMovement = new wxStaticText(m_PageReal, wxID_ANY, wxT("Movement name"), wxDefaultPosition, wxSize(200, 15), wxALIGN_CENTRE);
wxStaticText * m_TextGame = new wxStaticText(m_PageReal, wxID_ANY, wxT("Game name"), wxDefaultPosition, wxSize(200, 15), wxALIGN_CENTRE);
wxStaticText * m_TextRecSped = new wxStaticText(m_PageReal, wxID_ANY, wxT("R. s."), wxDefaultPosition, wxSize(30, 15), wxALIGN_CENTRE);
wxStaticText * m_TextPlaySpeed = new wxStaticText(m_PageReal, wxID_ANY, wxT("Pl. s."), wxDefaultPosition, wxSize(40, 15), wxALIGN_CENTRE);
m_TextRec->SetToolTip(wxT("Press this button, then start the recording by pressing 'A' on the Wiimote and stop the recording by pressing"
" 'A' again."));
m_TextRecSped->SetToolTip(wxT("Recording speed"));
m_TextPlaySpeed->SetToolTip(wxT("Playback speed"));
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_TextHotKey->SetToolTip(wxT("The HotKey is Shift + [Number] for Wiimote movements and Ctrl + [Number] for Nunchuck movements"));
m_TextRecSped->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 not nearly enough to say that it was 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), 8);
sRealRecord[0]->Add(m_TextRec, 0, wxEXPAND | (wxLEFT), 5);
sRealRecord[0]->Add(m_TextHotKey, 0, wxEXPAND | (wxLEFT), 5);
sRealRecord[0]->Add(m_TextMovement, 0, wxEXPAND | (wxLEFT), 5);
sRealRecord[0]->Add(m_TextGame, 0, wxEXPAND | (wxLEFT), 5);
@ -257,28 +422,28 @@ void ConfigDialog::CreateGUIControls()
sRealRecord[0]->Add(m_TextPlaySpeed, 0, wxEXPAND | (wxLEFT), 5);
sbRealRecord->Add(sRealRecord[0], 0, wxEXPAND | (wxALL), 0);
for(int i = 1; i < RECORDING_ROWS; i++)
for(int i = 1; i < (RECORDING_ROWS + 1); i++)
{
sRealRecord[i] = new wxBoxSizer(wxHORIZONTAL);
m_RecordButton[i] = new wxButton(m_PageReal, IDB_RECORD, wxEmptyString, wxDefaultPosition, wxSize(21, 14), 0, wxDefaultValidator, wxEmptyString);
m_RecordButton[i] = new wxButton(m_PageReal, IDB_RECORD + i, wxEmptyString, wxDefaultPosition, wxSize(80, 20), 0, wxDefaultValidator, wxEmptyString);
m_RecordHotKey[i] = new wxChoice(m_PageReal, IDC_RECORD, wxDefaultPosition, wxDefaultSize, StrHotKey);
m_RecordText[i] = new wxTextCtrl(m_PageReal, IDT_RECORD_TEXT, wxT(""), wxDefaultPosition, wxSize(250, 19));
m_RecordGameText[i] = new wxTextCtrl(m_PageReal, IDT_RECORD_GAMETEXT, wxT(""), wxDefaultPosition, wxSize(250, 19));
m_RecordText[i] = new wxTextCtrl(m_PageReal, IDT_RECORD_TEXT, wxT(""), wxDefaultPosition, wxSize(200, 19));
m_RecordGameText[i] = new wxTextCtrl(m_PageReal, IDT_RECORD_GAMETEXT, wxT(""), wxDefaultPosition, wxSize(200, 19));
m_RecordSpeed[i] = new wxTextCtrl(m_PageReal, IDT_RECORD_SPEED, wxT(""), wxDefaultPosition, wxSize(30, 19), wxTE_READONLY | wxTE_CENTRE);
m_RecordPlayBackSpeed[i] = new wxChoice(m_PageReal, IDT_RECORD_PLAYSPEED, wxDefaultPosition, wxDefaultSize, StrPlayBackSpeed);
m_RecordText[i]->SetMaxLength(50);
m_RecordGameText[i]->SetMaxLength(50);
m_RecordText[i]->SetMaxLength(35);
m_RecordGameText[i]->SetMaxLength(35);
m_RecordSpeed[i]->Enable(false);
sRealRecord[i]->Add(m_RecordButton[i], 0, wxEXPAND | (wxALL), 5);
sRealRecord[i]->Add(m_RecordHotKey[i], 0, wxEXPAND | (wxALL), 5);
sRealRecord[i]->Add(m_RecordText[i], 0, wxEXPAND | (wxALL), 5);
sRealRecord[i]->Add(m_RecordGameText[i], 0, wxEXPAND | (wxALL), 5);
sRealRecord[i]->Add(m_RecordSpeed[i], 0, wxEXPAND | (wxALL), 5);
sRealRecord[i]->Add(m_RecordPlayBackSpeed[i], 0, wxEXPAND | (wxALL), 5);
sRealRecord[i]->Add(m_RecordButton[i], 0, wxEXPAND | (wxLEFT), 5);
sRealRecord[i]->Add(m_RecordHotKey[i], 0, wxEXPAND | (wxLEFT), 5);
sRealRecord[i]->Add(m_RecordText[i], 0, wxEXPAND | (wxLEFT), 5);
sRealRecord[i]->Add(m_RecordGameText[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 | (wxALL), 0);
sbRealRecord->Add(sRealRecord[i], 0, wxEXPAND | (wxTOP), 2);
}
// ==========================================
@ -289,10 +454,14 @@ void ConfigDialog::CreateGUIControls()
sbRealBasic->Add(m_ConnectRealWiimote, 0, wxEXPAND | (wxALL), 5);
sbRealBasic->Add(m_UseRealWiimote, 0, wxEXPAND | (wxALL), 5);
wxBoxSizer * sRealBasicStatus = new wxBoxSizer(wxHORIZONTAL);
sRealBasicStatus->Add(sbRealBasic, 0, wxEXPAND | (wxLEFT), 0);
sRealBasicStatus->Add(sbRealStatus, 0, wxEXPAND | (wxLEFT), 5);
wxBoxSizer * sRealMain = new wxBoxSizer(wxVERTICAL);
sRealMain->Add(sbRealBasic, 0, wxEXPAND | (wxALL), 5);
sRealMain->Add(sbRealStatus, 0, wxEXPAND | (wxLEFT | wxLEFT | wxDOWN), 5);
sRealMain->Add(sbRealRecord, 0, wxEXPAND | (wxLEFT | wxLEFT | wxDOWN), 5);
sRealMain->Add(sRealBasicStatus, 0, wxEXPAND | (wxALL), 5);
sRealMain->Add(sbRealWiimoteStatus, 0, wxEXPAND | (wxLEFT | wxRIGHT | wxDOWN), 5);
sRealMain->Add(sbRealRecord, 0, wxEXPAND | (wxLEFT | wxRIGHT | wxDOWN), 5);
/////////////////////////////////
@ -308,28 +477,164 @@ void ConfigDialog::CreateGUIControls()
Fit();
Center();
ControlsCreated = true;
/////////////////////////////////
}
void ConfigDialog::OnClose(wxCloseEvent& WXUNUSED (event))
{
g_Config.Save();
EndModal(0);
}
void ConfigDialog::CloseClick(wxCommandEvent& WXUNUSED (event))
{
Close();
}
void ConfigDialog::AboutClick(wxCommandEvent& WXUNUSED (event))
{
}
/////////////////////////////////
//void ConfigDialog::Update()
/////////////////////////////////////////////////////////////////////////
/* Record movement */
// ------------
void ConfigDialog::ConvertToString()
{
// Load ini file
IniFile file;
file.Load("WiimoteMovement.ini");
std::string TmpStr = "", TmpTime = "";
for (int i = 0; i < m_vRecording.size(); i++)
{
// Write the movement data
TmpStr += StringFromFormat("%02x", m_vRecording.at(i).x);
TmpStr += StringFromFormat("%02x", m_vRecording.at(i).y);
TmpStr += StringFromFormat("%02x", m_vRecording.at(i).z);
if(i < (m_vRecording.size() - 1)) TmpStr += ",";
/* 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))
{
break;
PanicAlert("Your recording was to long, the entire recording was not saved.");
}
// 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 < (m_vRecording.size() - 1)) TmpTime += ",";
//Console::Print("Time: %f %i\n", m_vRecording.at(i).Time, Time);
}
// 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);
m_RecordSpeed[m_iRecordTo]->SetValue(wxString::Format(wxT("%i"), Rate));
std::string SaveName = StringFromFormat("Recording%i", m_iRecordTo);
file.Set(SaveName.c_str(), "Movement", TmpStr.c_str());
file.Set(SaveName.c_str(), "Time", TmpTime.c_str());
file.Set(SaveName.c_str(), "RecordingSpeed", Rate);
file.Save("WiimoteMovement.ini");
}
// Timeout the recording
void ConfigDialog::Update(wxTimerEvent& WXUNUSED(event))
{
m_bWaitForRecording = false;
m_bRecording = false;
m_RecordButton[m_iRecordTo]->SetLabel("");
UpdateGUI();
}
// One second timeout for another A press
void ConfigDialog::UpdateA(wxTimerEvent& WXUNUSED(event))
{
m_bAllowA = true;
Console::Print("A allowed again");
}
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("Hold A");
}
else
{
m_RecordButton[m_iRecordTo]->SetLabel("Press +");
return;
}
m_bWaitForRecording = true;
m_bAllowA = true;
m_bRecording = false;
UpdateGUI();
m_TimeoutTimer->Start(5000, true);
//m_TimeoutATimer->Start(500, 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("Recording...");
m_vRecording.clear(); // Clear the list
m_TimeoutTimer->Stop();
m_bWaitForRecording = false;
}
// The recording is done
else
{
m_RecordButton[m_iRecordTo]->SetLabel("Done");
Console::Print("Done: %i %i\n", m_bWaitForRecording, m_bRecording);
//m_bAllowA = true;
ConvertToString();
}
UpdateGUI();
}
void ConfigDialog::DoRecordMovement(u8 _x, u8 _y, u8 _z)
{
if (!m_bRecording) return;
Console::Print("DoRecordMovement\n");
SRecording Tmp;
Tmp.x = _x;
Tmp.y = _y;
Tmp.z = _z;
Tmp.Time = GetDoubleTime();
m_vRecording.push_back(Tmp);
/* 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("Done");
ConvertToString();
UpdateGUI();
}
}
/////////////////////////////////
/////////////////////////////////////////////////////////////////////////
@ -493,10 +798,12 @@ void ConfigDialog::GeneralSettingsChanged(wxCommandEvent& event)
case ID_CONNECT_REAL:
DoConnectReal();
break;
case ID_USE_REAL:
g_Config.bUseRealWiimote = m_UseRealWiimote->IsChecked();
break;
case ID_UPDATE_REAL:
g_Config.bUpdateRealWiimote = m_UpdateMeters->IsChecked();
break;
/////////////////
}
g_Config.Save();
@ -510,6 +817,8 @@ void ConfigDialog::GeneralSettingsChanged(wxCommandEvent& event)
// -------------
void ConfigDialog::UpdateGUI()
{
Console::Print("UpdateGUI: \n");
/* 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
@ -517,5 +826,7 @@ void ConfigDialog::UpdateGUI()
for that so that this option can be enabled during gameplay. */
m_ConnectRealWiimote->Enable(!g_EmulatorRunning);
m_UseRealWiimote->Enable(g_RealWiiMotePresent && g_Config.bConnectRealWiimote);
Console::Print("Present: %i, Connect: %i\n", g_RealWiiMotePresent, g_Config.bConnectRealWiimote);
for(int i = IDB_RECORD + 1; i < (IDB_RECORD + RECORDING_ROWS + 1); i++)
if(ControlsCreated) m_Notebook->FindItem(i)->Enable(!(m_bWaitForRecording || m_bRecording));
}

View File

@ -18,6 +18,9 @@
#ifndef __CONFIGDIALOG_h__
#define __CONFIGDIALOG_h__
#include <iostream>
#include <vector>
#include <wx/wx.h>
#include <wx/dialog.h>
#include <wx/textctrl.h>
@ -30,7 +33,6 @@
#include <wx/filepicker.h>
#include <wx/gbsizer.h>
class ConfigDialog : public wxDialog
{
public:
@ -40,17 +42,33 @@ class ConfigDialog : public wxDialog
long style = wxDEFAULT_DIALOG_STYLE);
virtual ~ConfigDialog();
// General open, close and event functions
void CloseClick(wxCommandEvent& event);
void UpdateGUI();
void OnKeyDown(wxKeyEvent& event);
void LoadFile(); void SaveFile();
// Status
wxStaticText * m_TextUpdateRate;
// Flash lights on connect functions
wxTimer * m_ExitTimer;
void DoFlashLights();
void StartTimer();
void FlashLights(wxTimerEvent& WXUNUSED(event)) { DoFlashLights(); }
bool ShutDown; int TimerCounter;
//void Update(wxTimerEvent& WXUNUSED(event));
// Wiimote status
wxGauge *m_GaugeBattery, *m_GaugeRoll[2], *m_GaugeGForce[3], *m_GaugeAccel[3];
bool m_bWaitForRecording, m_bRecording, m_bAllowA;
int m_iRecordTo;
void RecordMovement(wxCommandEvent& event);
void DoRecordMovement(u8 _x, u8 _y, u8 _z);
void DoRecordA(bool Pressed);
void ConvertToString();
wxTimer *m_TimeoutTimer, *m_TimeoutATimer;
void Update(wxTimerEvent& WXUNUSED(event));
void UpdateA(wxTimerEvent& WXUNUSED(event));
private:
DECLARE_EVENT_TABLE();
@ -60,25 +78,38 @@ class ConfigDialog : public wxDialog
wxNotebook *m_Notebook;
wxPanel *m_PageEmu, *m_PageReal;
bool ControlsCreated;
wxCheckBox *m_SidewaysDPad; // Emulated Wiimote settings
wxCheckBox *m_WideScreen;
wxCheckBox *m_NunchuckConnected, *m_ClassicControllerConnected;
wxCheckBox *m_ConnectRealWiimote, *m_UseRealWiimote; // Real Wiimote settings
wxCheckBox *m_ConnectRealWiimote, *m_UseRealWiimote, *m_UpdateMeters; // Real Wiimote settings
static const int RECORDING_ROWS = 11;
wxButton * m_RecordButton[RECORDING_ROWS];
wxChoice * m_RecordHotKey[RECORDING_ROWS];
wxTextCtrl * m_RecordText[RECORDING_ROWS];
wxTextCtrl * m_RecordGameText[RECORDING_ROWS];
wxTextCtrl * m_RecordSpeed[RECORDING_ROWS];
wxChoice * m_RecordPlayBackSpeed[RECORDING_ROWS];
//static const int RECORDING_ROWS = 15;
wxButton * m_RecordButton[RECORDING_ROWS + 1];
wxChoice * m_RecordHotKey[RECORDING_ROWS + 1];
wxTextCtrl * m_RecordText[RECORDING_ROWS + 1];
wxTextCtrl * m_RecordGameText[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<SRecording> m_vRecording;
enum
{
ID_CLOSE = 1000,
ID_ABOUTOGL,
IDTM_EXIT, IDTM_UPDATE, // Timer
IDTM_EXIT, IDTM_UPDATE, IDTM_UPDATEA, // Timer
ID_NOTEBOOK,
ID_PAGEEMU,
@ -89,13 +120,14 @@ class ConfigDialog : public wxDialog
ID_NUNCHUCKCONNECTED, ID_CLASSICCONTROLLERCONNECTED,
// Real
ID_CONNECT_REAL, ID_USE_REAL, IDT_STATUS,
IDB_RECORD, IDC_RECORD, IDT_RECORD_TEXT, IDT_RECORD_GAMETEXT, IDT_RECORD_SPEED, IDT_RECORD_PLAYSPEED
ID_CONNECT_REAL, ID_USE_REAL, ID_UPDATE_REAL, IDT_STATUS,
IDB_RECORD = 2000,
IDC_RECORD = 3000,
IDT_RECORD_TEXT, IDT_RECORD_GAMETEXT, IDT_RECORD_SPEED, IDT_RECORD_PLAYSPEED
};
void OnClose(wxCloseEvent& event);
void CreateGUIControls();
void AboutClick(wxCommandEvent& event);
void DoConnectReal(); // Real
@ -105,4 +137,6 @@ class ConfigDialog : public wxDialog
void GeneralSettingsChanged(wxCommandEvent& event);
};
extern ConfigDialog *frame;
#endif

View File

@ -26,8 +26,9 @@
#include "Common.h" // Common
#include "StringUtil.h" // for ArrayToString()
#include "IniFile.h"
#include "main.h"
#include "main.h" // Local
#include "wiimote_hid.h"
#include "EmuSubroutines.h"
#include "EmuDefinitions.h"
@ -137,6 +138,61 @@ void Initialize()
g_EmulatedWiiMoteInitialized = true;
//////////////////////////////////////
// Load pre-recorded movements
// ---------------
IniFile file;
file.Load("WiimoteMovement.ini");
for(int i = 0; i < RECORDING_ROWS; i++)
{
// Get row name
std::string SaveName = StringFromFormat("Recording%i", i + 1);
// Get movement
std::string TmpMovement; file.Get(SaveName.c_str(), "Movement", &TmpMovement, "");
// Get time
std::string TmpTime; file.Get(SaveName.c_str(), "Time", &TmpTime, "");
SRecording Tmp;
for (int j = 0, k = 0; j < TmpMovement.length(); j+=7)
{
// Skip blank savings
if (TmpMovement.length() < 3) continue;
std::string StrX = TmpMovement.substr(j, 2);
std::string StrY = TmpMovement.substr(j + 2, 2);
std::string StrZ = TmpMovement.substr(j + 4, 2);
u32 TmpX, TmpY, TmpZ;
AsciiToHex(StrX.c_str(), TmpX);
AsciiToHex(StrY.c_str(), TmpY);
AsciiToHex(StrZ.c_str(), TmpZ);
Tmp.x = (u8)TmpX;
Tmp.x = (u8)TmpY;
Tmp.x = (u8)TmpZ;
// Go to next set of time values
int Time = atoi(TmpTime.substr(k, 5).c_str());
Tmp.Time = (double)(Time/1000);
VRecording.at(i).Recording.push_back(Tmp);
k += 6;
}
// HotKey
int TmpRecordHotKey; file.Get(SaveName.c_str(), "HotKey", &TmpRecordHotKey, -1);
VRecording.at(i).HotKey = TmpRecordHotKey;
// Recording speed
int TmpPlaybackSpeed; file.Get(SaveName.c_str(), "PlaybackSpeed", &TmpPlaybackSpeed, -1);
VRecording.at(i).PlaybackSpeed = TmpPlaybackSpeed;
Console::Print("Size:%i HotKey:%i Speed:%i\n",
VRecording.at(i).Recording.size(), VRecording.at(i).HotKey, VRecording.at(i).PlaybackSpeed
);
}
//////////////////////////
// I forgot what these were for?
// g_RegExt[0xfd] = 0x1e;
// g_RegExt[0xfc] = 0x9a;

View File

@ -46,9 +46,12 @@ namespace WiiMoteEmu
//******************************************************************************
////////////////////////////////////////////////////////////
// Wiimote core buttons
// ---------------
void FillReportInfo(wm_core& _core)
{
/* This has to be filled with zeroes because when no buttons are pressed the
/* 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));
@ -67,9 +70,7 @@ void FillReportInfo(wm_core& _core)
_core.home = GetAsyncKeyState('H') ? 1 : 0;
/* Sideways controls (for example for Wario Land) was not enabled automatically
so I have to use this function. I'm not sure how it works on the actual Wii.
*/
/* Sideways controls (for example for Wario Land) if the Wiimote is intended to be held sideways */
if(g_Config.bSidewaysDPad)
{
_core.left = GetAsyncKeyState(VK_DOWN) ? 1 : 0;
@ -88,15 +89,18 @@ void FillReportInfo(wm_core& _core)
// TODO: fill in
#endif
}
//////////////////////////
// -----------------------------
/* Global declarations for FillReportAcc. 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 the mouse pointer can disappear from the screen
permanently then, until z is adjusted back. */
////////////////////////////////////////////////////////////
// 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. */
// ----------
// the variables are global so they can be changed during debugging
// 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;
@ -283,6 +287,7 @@ void FillReportAcc(wm_accel& _acc)
AX, AY, AZ
);*/
}
/////////////////////////
void FillReportIR(wm_ir_extended& _ir0, wm_ir_extended& _ir1)
@ -459,7 +464,7 @@ void FillReportIRBasic(wm_ir_basic& _ir0, wm_ir_basic& _ir1)
int abc = 0;
// ===================================================
/* Generate the 6 byte extension report, encrypted. The bytes are JX JY AX AY AZ BT. */
/* Generate the 6 byte extension report for the Nunchuck, encrypted. The bytes are JX JY AX AY AZ BT. */
// ----------------
void FillReportExtension(wm_extension& _ext)
{
@ -529,6 +534,7 @@ void FillReportExtension(wm_extension& _ext)
// Write it back to the extension
memcpy(&_ext, &g_RegExtTmpReport[0x08], sizeof(_ext));
}
// =======================
// ===================================================
@ -706,6 +712,7 @@ void FillReportClassicExtension(wm_classic_extension& _ext)
// Write it back
memcpy(&_ext, &g_RegExtTmpReport[0x08], sizeof(_ext));
}
// =======================
} // end of namespace

View File

@ -28,7 +28,11 @@
#include "StringUtil.h"
#include "wiimote_real.h" // Local
#include "main.h" // Local
#include "main.h"
#if defined(HAVE_WX) && HAVE_WX
#include "ConfigDlg.h"
#endif
#include "Config.h"
////////////////////////////////////////
namespace WiiMoteReal
@ -68,13 +72,19 @@ void handle_event(struct wiimote_t* wm)
* This is useful because it saves battery power.
*/
if (IS_JUST_PRESSED(wm, WIIMOTE_BUTTON_MINUS))
{
wiiuse_motion_sensing(wm, 0);
g_MotionSensing = false;
}
/*
* Pressing plus will tell the wiimote we are interested in movement.
*/
if (IS_JUST_PRESSED(wm, WIIMOTE_BUTTON_PLUS))
{
wiiuse_motion_sensing(wm, 1);
g_MotionSensing = true;
}
/* If the accelerometer is turned on then print angles */
if (WIIUSE_USING_ACC(wm))
@ -85,22 +95,30 @@ void handle_event(struct wiimote_t* wm)
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\n", wm->accel.x, wm->accel.y, wm->accel.z);
Console::Print("%s", Tmp.c_str());
//Console::Print("%s", Tmp.c_str());
if(frame)
{
frame->m_GaugeBattery->SetValue((int)floor((wm->battery_level * 100) + 0.5));
if(g_Config.bUpdateRealWiimote)
{
frame->m_GaugeBattery->SetValue((int)floor((wm->battery_level * 100) + 0.5));
frame->m_GaugeRoll[0]->SetValue(wm->orient.roll + 180);
frame->m_GaugeRoll[1]->SetValue(wm->orient.pitch + 180);
frame->m_GaugeRoll[0]->SetValue(wm->orient.roll + 180);
frame->m_GaugeRoll[1]->SetValue(wm->orient.pitch + 180);
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_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_GaugeAccel[0]->SetValue(wm->accel.x);
frame->m_GaugeAccel[1]->SetValue(wm->accel.y);
frame->m_GaugeAccel[2]->SetValue(wm->accel.z);
}
frame->DoRecordMovement(wm->accel.x, wm->accel.y, wm->accel.z);
if (IS_PRESSED(wm, WIIMOTE_BUTTON_A)) frame->DoRecordA(true);
else frame->DoRecordA(false);
}
}
}

View File

@ -20,17 +20,16 @@
// Includes
// ¯¯¯¯¯¯¯¯¯¯¯¯¯
#include "Common.h" // Common
#include "Config.h"
#include "StringUtil.h"
#include "ConsoleWindow.h" // For Start, Print, GetHwnd
#if defined(HAVE_WX) && HAVE_WX
#include <wx/aboutdlg.h>
#include "ConfigDlg.h"
#endif
#include "Timer.h"
#define EXCLUDEMAIN_H // Avoid certain declarations in main.h
#include "main.h" // Local
#if defined(HAVE_WX) && HAVE_WX
#include "ConfigDlg.h"
#endif
#include "Config.h"
#include "pluginspecs_wiimote.h"
#include "EmuMain.h"
#if HAVE_WIIUSE
@ -50,6 +49,17 @@ bool g_RealWiiMotePresent = false;
bool g_RealWiiMoteInitialized = false;
bool g_EmulatedWiiMoteInitialized = false;
// Update speed
int g_UpdateCounter = 0;
double g_UpdateTime = 0;
int g_UpdateRate = 0;
int g_UpdateWriteScreen = 0;
std::vector<int> g_UpdateTimeList (5, 0);
// Movement recording
std::vector<SRecordingAll> VRecording(RECORDING_ROWS);
// DLL instance
HINSTANCE g_hInstance;
#if defined(HAVE_WX) && HAVE_WX
@ -134,6 +144,8 @@ void DllConfig(HWND _hParent)
win.SetHWND(_hParent);
#endif
Console::Open();
g_FrameOpen = true;
frame = new ConfigDialog(&win);
@ -266,6 +278,18 @@ extern "C" void Wiimote_ControlChannel(u16 _channelID, const void* _pData, u32 _
// ----------------
extern "C" void Wiimote_Update()
{
// Tell us about the update rate, but only about once every second to avoid a major slowdown
if (frame)
{
GetUpdateRate();
if (g_UpdateWriteScreen > g_UpdateRate)
{
frame->m_TextUpdateRate->SetLabel(wxString::Format("Update rate: %03i times/s", g_UpdateRate));
g_UpdateWriteScreen = 0;
}
g_UpdateWriteScreen++;
}
if (!g_Config.bUseRealWiimote || !g_RealWiiMotePresent)
WiiMoteEmu::Update();
#if HAVE_WIIUSE
@ -285,17 +309,79 @@ extern "C" unsigned int Wiimote_GetAttachedControllers()
// Supporting functions
//******************************************************************************
/* 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);
//Console::Print("Time: %i %f\n", Time, GetDoubleTime());
int TotalTime = 0;
for (int i = 0; i < 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()
{
// ----------------------------------------
// Debugging window
// ----------
/*Console::Open(100, 750, "Wiimote"); // give room for 20 rows
/**/Console::Open(100, 750, "Wiimote"); // give room for 20 rows
Console::Print("Wiimote console opened\n");
// Move window
//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(), 400,0, 100*8,70*14, true); // big window
// ---------------
// Load config settings

View File

@ -22,9 +22,6 @@
// Includes
// ¯¯¯¯¯¯¯¯¯¯
#include <iostream> // System
#if defined(HAVE_WX) && HAVE_WX
#include "ConfigDlg.h"
#endif
////////////////////////////////
@ -41,6 +38,24 @@
// Declarations
// ¯¯¯¯¯¯¯¯¯
void DoInitialize();
double GetDoubleTime();
int GetUpdateRate();
// Movement recording
#define RECORDING_ROWS 15
struct SRecording
{
u8 x;
u8 y;
u8 z;
double Time;
};
struct SRecordingAll
{
std::vector<SRecording> Recording;
int HotKey;
int PlaybackSpeed;
};
#ifndef EXCLUDEMAIN_H
extern bool g_EmulatorRunning;
@ -48,10 +63,20 @@ void DoInitialize();
extern bool g_RealWiiMotePresent;
extern bool g_RealWiiMoteInitialized;
extern bool g_EmulatedWiiMoteInitialized;
// Update speed
extern int g_UpdateCounter;
extern double g_UpdateTime;
extern int g_UpdateWriteScreen;
extern int g_UpdateRate;
extern std::vector<int> g_UpdateTimeList;
#if defined(HAVE_WX) && HAVE_WX
extern ConfigDialog *frame;
#endif
// Movement recording
extern std::vector<SRecordingAll> VRecording;
//#if defined(HAVE_WX) && HAVE_WX && defined(__CONFIGDIALOG_h__)
// extern ConfigDialog *frame;
//#endif
#endif
////////////////////////////////

View File

@ -32,8 +32,9 @@
#include "wiimote_hid.h"
#include "main.h"
#include "Config.h"
#include "EmuMain.h"
#define EXCLUDE_H // Avoid certain declarations in main.h
#define EXCLUDE_H // Avoid certain declarations in wiimote_real.h
#include "wiimote_real.h"
#if defined(HAVE_WX) && HAVE_WX
#include "ConfigDlg.h"
@ -67,6 +68,7 @@ int g_NumberOfWiiMotes;
CWiiMote* g_WiiMotes[MAX_WIIMOTES];
bool g_Shutdown = false;
bool g_LocalThread = true;
bool g_MotionSensing = false;
//******************************************************************************
// Probably this class should be in its own file
@ -121,8 +123,10 @@ void SendData(u16 _channelID, const u8* _pData, u32 _Size)
/////////////////////
//////////////////////////////////////////
// Read data from wiimote (but don't send it to the core, just filter and queue)
//////////////////////////////////////////////////
/* Read data from wiimote (but don't send it to the core, just filter and queue). If we are not currently
using the real Wiimote we only allow it to receive data mode changes, but don't ask for any data in
return */
// ---------------
void ReadData()
{
@ -131,6 +135,7 @@ void ReadData()
// Send data to the Wiimote
if (!m_EventWriteQueue.empty())
{
Console::Print("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();
@ -138,35 +143,37 @@ void ReadData()
m_pCriticalSection->Leave();
if (wiiuse_io_read(m_pWiiMote))
{
const byte* pBuffer = m_pWiiMote->event_buf;
// Don't queue up data if we are not using the real Wiimote
if(g_Config.bUseRealWiimote)
if (wiiuse_io_read(m_pWiiMote))
{
const byte* pBuffer = m_pWiiMote->event_buf;
// Check if we have a channel (connection) if so save the data...
if (m_channelID > 0)
{
m_pCriticalSection->Enter();
// Check if we have a channel (connection) if so save the data...
if (m_channelID > 0)
{
m_pCriticalSection->Enter();
// Filter out 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);
m_EventReadQueue.push(ImportantEvent);
}
m_pCriticalSection->Leave();
}
// Filter out 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);
m_EventReadQueue.push(ImportantEvent);
}
m_pCriticalSection->Leave();
}
//std::string Temp = ArrayToString(pBuffer, sizeof(pBuffer), 0);
//Console::Print("Data:\n%s\n", Temp.c_str());
}
//std::string Temp = ArrayToString(pBuffer, sizeof(pBuffer), 0);
//Console::Print("Data:\n%s\n", Temp.c_str());
}
};
/////////////////////
@ -181,10 +188,12 @@ void Update()
if (m_EventReadQueue.empty())
{
// Send the same data as last time
if (m_LastReportValid) SendEvent(m_LastReport);
}
else
{
// Send all the new data we have collected
SendEvent(m_EventReadQueue.front());
m_EventReadQueue.pop();
}
@ -352,7 +361,11 @@ void Update()
}
//////////////////////////////////
// Continuously read the Wiimote status
/* 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. Todo: Figure
out how to manually send the current data reporting mode to the real Wiimote so that we can entirely turn
off ReadData() (including wiiuse_io_write()) while we are not using the real wiimote. For example to risk
interrupting accelerometer recordings by a wiiuse_io_write(). */
// ---------------
#ifdef _WIN32
DWORD WINAPI ReadWiimote_ThreadFunc(void* arg)
@ -364,7 +377,7 @@ void Update()
{
if(g_EmulatorRunning)
for (int i = 0; i < g_NumberOfWiiMotes; i++) g_WiiMotes[i]->ReadData();
else
else if (!g_Config.bUseRealWiimote)
ReadWiimote();
}
return 0;

View File

@ -43,6 +43,7 @@ void ReadWiimote();
#ifndef EXCLUDE_H
extern wiimote_t** g_WiiMotesFromWiiUse;
extern int g_NumberOfWiiMotes;
extern bool g_MotionSensing;
#endif
}; // WiiMoteReal