mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-01-27 00:05:34 +01:00
fcdd2a8e17
1. Fixed the dual mode. You should now be able to change between the real and emulated Wiimote at any time, even when the Nunchuck is connected. It also supports third party Wireless Nunchucks that never sends any calibration values. The Nunchuck status should be automatically updated. The Nunchuck stick may get stuck, but that should fix itself if you disconnect and reconnect again. The only important problems seems to be that the real Wiimote fails to answer sometimes so that the Core functions disconnect it. 2. Began looking at how to reconnect the Wiimote after an unwanted HCI disconnect command git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@2129 8ced0084-cf51-0410-be5f-012b33b47a6e
1010 lines
26 KiB
C++
1010 lines
26 KiB
C++
// Copyright (C) 2003-2008 Dolphin Project.
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, version 2.0.
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License 2.0 for more details.
|
|
|
|
// A copy of the GPL 2.0 should have been included with the program.
|
|
// If not, see http://www.gnu.org/licenses/
|
|
|
|
// Official SVN repository and contact information can be found at
|
|
// http://code.google.com/p/dolphin-emu/
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
// Includes
|
|
// ¯¯¯¯¯¯¯¯¯¯¯¯¯
|
|
#include <wx/msgdlg.h>
|
|
|
|
#include <vector>
|
|
#include <string>
|
|
|
|
#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;
|
|
// --------------------------
|
|
|
|
template<class IRReportType>
|
|
bool RecordingPlayAccIR(u8 &_x, u8 &_y, u8 &_z, IRReportType &_IR, int Wm)
|
|
{
|
|
// Return if the list is empty
|
|
if(VRecording.at(g_RecordingPlaying[Wm]).Recording.size() == 0)
|
|
{
|
|
g_RecordingPlaying[Wm] = -1;
|
|
Console::Print("Empty\n\n");
|
|
return false;
|
|
}
|
|
|
|
// Return if the playback speed is unset
|
|
if(VRecording.at(g_RecordingPlaying[Wm]).PlaybackSpeed < 0)
|
|
{
|
|
Console::Print("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))
|
|
)
|
|
)
|
|
{
|
|
Console::Print("Wrong IR mode: %i\n\n", g_RecordingPlaying[Wm]);
|
|
g_RecordingPlaying[Wm] = -1;
|
|
return false;
|
|
}
|
|
|
|
// Get starting time
|
|
if(g_RecordingCounter[Wm] == 0)
|
|
{
|
|
Console::Print("\n\nBegin\n");
|
|
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 < 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)
|
|
{
|
|
g_RecordingCounter[Wm] = 0;
|
|
g_RecordingPlaying[Wm] = -1;
|
|
g_RecordingStart[Wm] = 0;
|
|
g_RecordingCurrentTime[Wm] = 0;
|
|
Console::Print("End\n\n");
|
|
return false;
|
|
}
|
|
|
|
// Update values
|
|
_x = VRecording.at(g_RecordingPlaying[Wm]).Recording.at(g_RecordingPoint[Wm]).x;
|
|
_y = VRecording.at(g_RecordingPlaying[Wm]).Recording.at(g_RecordingPoint[Wm]).y;
|
|
_z = VRecording.at(g_RecordingPlaying[Wm]).Recording.at(g_RecordingPoint[Wm]).z;
|
|
if(Wm == WM_RECORDING_IR) memcpy(&_IR, VRecording.at(g_RecordingPlaying[Wm]).Recording.at(g_RecordingPoint[Wm]).IR, IRBytes);
|
|
|
|
/**/
|
|
if (g_DebugAccelerometer)
|
|
{
|
|
Console::ClearScreen();
|
|
Console::Print("Current time: %f %f %i %i\n",
|
|
VRecording.at(g_RecordingPlaying[Wm]).Recording.at(g_RecordingPoint[Wm]).Time, g_RecordingCurrentTime[Wm],
|
|
VRecording.at(g_RecordingPlaying[Wm]).Recording.size(), g_RecordingPoint[Wm]
|
|
);
|
|
Console::Print("Accel x, y, z: %03u %03u %03u\n\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<class IRReportType>
|
|
bool RecordingPlayIR(IRReportType &_IR)
|
|
{
|
|
u8 x, y, z;
|
|
return RecordingPlayAccIR(x, y, z, _IR, 2);
|
|
}
|
|
|
|
// Check if we should start the playback of a recording. Once it has been started it can not currently
|
|
// be stopped, it will always run to the end of the recording.
|
|
int RecordingCheckKeys(int Wiimote)
|
|
{
|
|
#ifdef _WIN32
|
|
//Console::Print("RecordingCheckKeys: %i\n", Wiimote);
|
|
|
|
// ------------------------------------
|
|
// Don't allow multiple action keys
|
|
// --------------
|
|
// Return if we have both a Shift, Ctrl, and Alt
|
|
if ( GetAsyncKeyState(VK_SHIFT) && GetAsyncKeyState(VK_CONTROL) && GetAsyncKeyState(VK_MENU) ) return -1;
|
|
// Return if we have both a Shift and Ctrl
|
|
if ( (GetAsyncKeyState(VK_SHIFT) && GetAsyncKeyState(VK_CONTROL)) ) return -1;
|
|
// Return if we have both a Ctrl and Alt
|
|
if ( (GetAsyncKeyState(VK_CONTROL) && GetAsyncKeyState(VK_MENU)) ) return -1;
|
|
// Return if we have both a Shift and Alt
|
|
if ( (GetAsyncKeyState(VK_SHIFT) && GetAsyncKeyState(VK_MENU)) ) return -1;
|
|
// ---------------------
|
|
|
|
// Return if we don't have both a Wiimote and Shift
|
|
if ( Wiimote == 0 && !GetAsyncKeyState(VK_SHIFT) ) return -1;
|
|
|
|
// Return if we don't have both a Nunchuck and Ctrl
|
|
if ( Wiimote == 1 && !GetAsyncKeyState(VK_CONTROL) ) return -1;
|
|
|
|
// Return if we don't have both a IR call and Alt
|
|
if ( Wiimote == 2 && !GetAsyncKeyState(VK_MENU) ) return -1;
|
|
|
|
// Check if we have exactly one numerical key
|
|
int Keys = 0;
|
|
for(int i = 0; i < 10; i++)
|
|
{
|
|
std::string Key = StringFromFormat("%i", i);
|
|
if(GetAsyncKeyState(Key[0])) Keys++;
|
|
}
|
|
|
|
//Console::Print("RecordingCheckKeys: %i\n", Keys);
|
|
|
|
// Return if we have less than or more than one
|
|
if (Keys != 1) return -1;
|
|
|
|
// Check which key it is
|
|
int Key;
|
|
for(int i = 0; i < 10; i++)
|
|
{
|
|
std::string TmpKey = StringFromFormat("%i", i);
|
|
if(GetAsyncKeyState(TmpKey[0])) { Key = i; break; }
|
|
}
|
|
|
|
// Check if we have a HotKey match
|
|
bool Match = false;
|
|
for(int i = 0; i < RECORDING_ROWS; i++)
|
|
{
|
|
if (VRecording.at(i).HotKey == Key)
|
|
{
|
|
//Console::Print("Match: %i %i\n", i, Key);
|
|
Match = true;
|
|
Key = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Return nothing if we don't have a match
|
|
if (!Match) return -1;
|
|
|
|
// Return the match
|
|
return Key;
|
|
#else
|
|
return -1;
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
//******************************************************************************
|
|
// Subroutines
|
|
//******************************************************************************
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// 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));
|
|
|
|
#ifdef _WIN32
|
|
// These keys are reserved for the recording
|
|
if ( GetAsyncKeyState(VK_SHIFT) || GetAsyncKeyState(VK_CONTROL) ) return;
|
|
|
|
// 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((GetAsyncKeyState(VK_LBUTTON) && InsideScreen) || GetAsyncKeyState('A') ? 1 : 0)
|
|
_core.a = 1;
|
|
|
|
if((GetAsyncKeyState(VK_RBUTTON) && InsideScreen) || GetAsyncKeyState('B') ? 1 : 0)
|
|
_core.b = 1;
|
|
|
|
_core.one = GetAsyncKeyState('1') ? 1 : 0;
|
|
_core.two = GetAsyncKeyState('2') ? 1 : 0;
|
|
_core.plus = GetAsyncKeyState('P') ? 1 : 0;
|
|
_core.minus = GetAsyncKeyState('M') ? 1 : 0;
|
|
_core.home = GetAsyncKeyState('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 = GetAsyncKeyState(VK_DOWN) ? 1 : 0;
|
|
_core.up = GetAsyncKeyState(VK_LEFT) ? 1 : 0;
|
|
_core.right = GetAsyncKeyState(VK_UP) ? 1 : 0;
|
|
_core.down = GetAsyncKeyState(VK_RIGHT) ? 1 : 0;
|
|
}
|
|
else
|
|
{
|
|
_core.left = GetAsyncKeyState(VK_LEFT) ? 1 : 0;
|
|
_core.up = GetAsyncKeyState(VK_UP) ? 1 : 0;
|
|
_core.right = GetAsyncKeyState(VK_RIGHT) ? 1 : 0;
|
|
_core.down = GetAsyncKeyState(VK_DOWN) ? 1 : 0;
|
|
}
|
|
#else
|
|
// TODO: fill in
|
|
#endif
|
|
}
|
|
//////////////////////////
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
// 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. */
|
|
// ----------
|
|
// 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;
|
|
|
|
u8 x, y, z;
|
|
int shake = -1, yhistsize = 15; // for the shake function
|
|
std::vector<u8> yhist(15); // for the tilt function
|
|
|
|
void FillReportAcc(wm_accel& _acc)
|
|
{
|
|
// Create shortcut names for the default neutral values
|
|
int X = g_accel.cal_zero.x, Y = g_accel.cal_zero.y, Z = g_accel.cal_zero.z + g_accel.cal_g.z;
|
|
|
|
#ifdef _WIN32
|
|
// ------------------------------------
|
|
// 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;
|
|
//Console::Print("X, Y, Z: %u %u %u\n", _acc.x, _acc.y, _acc.z);
|
|
}
|
|
// ---------------------
|
|
|
|
|
|
// Check that Dolphin is in focus
|
|
if (!IsFocus())
|
|
{
|
|
_acc.x = X;
|
|
_acc.y = y;
|
|
_acc.z = z;
|
|
return;
|
|
}
|
|
|
|
// ------------------------------------
|
|
// Wiimote to Gamepad translations
|
|
// ----------
|
|
// Tilting Wiimote (Wario Land aiming, Mario Kart steering) : For some reason 150 and 40
|
|
// seemed like decent starting values.
|
|
if(GetAsyncKeyState('3'))
|
|
{
|
|
//if(a < 128) // for debugging
|
|
if(y < 250)
|
|
{
|
|
y += 4; // aim left
|
|
//a += c; // debugging values
|
|
//y = A + a; // aim left
|
|
}
|
|
}
|
|
else if(GetAsyncKeyState('4'))
|
|
{
|
|
// if(b < 128) // for debugging
|
|
if(y > 5)
|
|
{
|
|
y -= 4; // aim right
|
|
//b -= d; // debugging values
|
|
//y = B + b;
|
|
}
|
|
}
|
|
|
|
/* Single shake of Wiimote while holding it sideways (Wario Land pound ground)
|
|
if(GetAsyncKeyState('S'))
|
|
z = 0;
|
|
else
|
|
z = Z;*/
|
|
|
|
if(GetAsyncKeyState('S'))
|
|
{
|
|
z = 0;
|
|
y = 0;
|
|
shake = 2;
|
|
}
|
|
else
|
|
#endif
|
|
if(shake == 2)
|
|
{
|
|
z = 128;
|
|
y = 0;
|
|
shake = 1;
|
|
}
|
|
else if(shake == 1)
|
|
{
|
|
z = Z;
|
|
y = Y;
|
|
shake = -1;
|
|
}
|
|
else // the default Z if nothing is pressed
|
|
{
|
|
z = Z;
|
|
}
|
|
// ----------
|
|
|
|
|
|
// -----------------------------
|
|
// For tilting: add new value and move all back
|
|
// ----------
|
|
bool ypressed = false;
|
|
|
|
#ifdef _WIN32
|
|
yhist[yhist.size() - 1] = (
|
|
GetAsyncKeyState('3') ? true : false
|
|
|| GetAsyncKeyState('4') ? true : false
|
|
|| shake > 0
|
|
);
|
|
#endif
|
|
if(yhistsize > (int)yhist.size()) yhistsize = (int)yhist.size();
|
|
for (int i = 1; i < yhistsize; i++)
|
|
{
|
|
yhist[i-1] = yhist[i];
|
|
if(yhist[i]) ypressed = true;
|
|
}
|
|
|
|
if(!ypressed) // y was not pressed a single time
|
|
{
|
|
y = Y; // this is the default value that will occur most of the time
|
|
//a = 0; // for debugging
|
|
//b = 0;
|
|
}
|
|
// else if(!GetAsyncKeyState('3') && !GetAsyncKeyState('4'))
|
|
// {
|
|
// perhaps start dropping acceleration back?
|
|
// }
|
|
// ----------
|
|
|
|
|
|
// Write values
|
|
_acc.x = X;
|
|
_acc.y = y;
|
|
_acc.z = 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)
|
|
Console::Print("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
|
|
);
|
|
Console::Print("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
|
|
);*/
|
|
}
|
|
/////////////////////////
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
// 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
|
|
{
|
|
//Console::Print("X, Y, Z: %u %u %u\n", _acc.x, _acc.y, _acc.z);
|
|
if (RecordingPlayIR(_ir0)) return;
|
|
}
|
|
// ---------------------
|
|
|
|
|
|
// --------------------------------------
|
|
/* The calibration is controlled by these values, their absolute value and
|
|
the relative distance between between them control the calibration. WideScreen mode
|
|
has its own settings. */
|
|
// ----------
|
|
int Top, Left, Right, Bottom, SensorBarRadius;
|
|
if(g_Config.bWideScreen)
|
|
{
|
|
Top = wTOP; Left = wLEFT; Right = wRIGHT;
|
|
Bottom = wBOTTOM; SensorBarRadius = wSENSOR_BAR_RADIUS;
|
|
}
|
|
else
|
|
{
|
|
Top = TOP; Left = LEFT; Right = RIGHT;
|
|
Bottom = BOTTOM; SensorBarRadius = SENSOR_BAR_RADIUS;
|
|
}
|
|
// ------------------
|
|
|
|
/* 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;
|
|
|
|
// --------------------------------------
|
|
// Actual position calculation
|
|
// ----------
|
|
int y0 = Top + (MouseY * (Bottom - Top));
|
|
int y1 = Top + (MouseY * (Bottom - Top));
|
|
|
|
int x0 = Left + (MouseX * (Right - Left)) - SensorBarRadius;
|
|
int x1 = Left + (MouseX * (Right - Left)) + SensorBarRadius;
|
|
|
|
x0 = 1023 - x0;
|
|
_ir0.x = x0 & 0xFF;
|
|
_ir0.y = y0 & 0xFF;
|
|
_ir0.size = 10;
|
|
_ir0.xHi = x0 >> 8;
|
|
_ir0.yHi = y0 >> 8;
|
|
|
|
x1 = 1023 - x1;
|
|
_ir1.x = x1 & 0xFF;
|
|
_ir1.y = y1 & 0xFF;
|
|
_ir1.size = 10;
|
|
_ir1.xHi = x1 >> 8;
|
|
_ir1.yHi = y1 >> 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)
|
|
Console::Print("x0:%03i x1:%03i y0:%03i y1:%03i irx0:%03i y0:%03i x1:%03i y1:%03i | T:%i L:%i R:%i B:%i S:%i\n",
|
|
x0, x1, y0, y1, _ir0.x, _ir0.y, _ir1.x, _ir1.y, Top, Left, Right, Bottom, SensorBarRadius
|
|
);
|
|
Console::Print("\n");
|
|
Console::Print("ir0.x:%02x xHi:%02x ir1.x:%02x xHi:%02x | ir0.y:%02x yHi:%02x ir1.y:%02x yHi:%02x | 1.s:%02x 2:%02x\n",
|
|
_ir0.x, _ir0.xHi, _ir1.x, _ir1.xHi,
|
|
_ir0.y, _ir0.yHi, _ir1.y, _ir1.yHi,
|
|
_ir0.size, _ir1.size
|
|
);*/
|
|
// ------------------
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
// 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
|
|
{
|
|
//Console::Print("X, Y, Z: %u %u %u\n", _acc.x, _acc.y, _acc.z);
|
|
if (RecordingPlayIR(_ir0)) return;
|
|
}
|
|
// ---------------------
|
|
|
|
// --------------------------------------
|
|
/* See calibration description above */
|
|
// ----------
|
|
int Top, Left, Right, Bottom, SensorBarRadius;
|
|
|
|
if(g_Config.bWideScreen)
|
|
{
|
|
Top = wTOP; Left = wLEFT; Right = wRIGHT;
|
|
Bottom = wBOTTOM; SensorBarRadius = wSENSOR_BAR_RADIUS;
|
|
}
|
|
else
|
|
{
|
|
Top = TOP; Left = LEFT; Right = RIGHT;
|
|
Bottom = BOTTOM; SensorBarRadius = SENSOR_BAR_RADIUS;
|
|
}
|
|
// ------------------
|
|
|
|
// 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 = Top + (MouseY * (Bottom - Top));
|
|
int y2 = Top + (MouseY * (Bottom - Top));
|
|
|
|
int x1 = Left + (MouseX * (Right - Left)) - SensorBarRadius;
|
|
int x2 = Left + (MouseX * (Right - Left)) + SensorBarRadius;
|
|
|
|
/* As with the extented report we settle with emulating two out of four possible objects */
|
|
x1 = 1023 - x1;
|
|
_ir0.x1 = x1 & 0xff;
|
|
_ir0.y1 = y1 & 0xff;
|
|
_ir0.x1Hi = (x1 >> 8); // we are dealing with 2 bit values here
|
|
_ir0.y1Hi = (y1 >> 8);
|
|
|
|
x2 = 1023 - x2;
|
|
_ir0.x2 = x2 & 0xff;
|
|
_ir0.y2 = y2 & 0xff;
|
|
_ir0.x2Hi = (x2 >> 8);
|
|
_ir0.y2Hi = (y2 >> 8);
|
|
|
|
// I don't understand't the & 0x03, should we do that?
|
|
//_ir1.x1Hi = (x1 >> 8) & 0x3;
|
|
//_ir1.y1Hi = (y1 >> 8) & 0x3;
|
|
|
|
// ------------------------------------
|
|
// 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)
|
|
|
|
Console::Print("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
|
|
);
|
|
Console::Print("\n");
|
|
Console::Print("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)))
|
|
{
|
|
/* These are the default neutral values for the nunchuck accelerometer according to the calibration
|
|
data we have in nunchuck_calibration[] */
|
|
_ext.ax = 0x80;
|
|
_ext.ay = 0x80;
|
|
_ext.az = 0xb3;
|
|
}
|
|
// ---------------------
|
|
|
|
// ------------------------------------
|
|
// 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
|
|
// ---------------------
|
|
|
|
#ifdef _WIN32
|
|
// Set the max values to the current calibration values
|
|
if(GetAsyncKeyState(VK_NUMPAD4)) // x
|
|
_ext.jx = g_nu.jx.min;
|
|
if(GetAsyncKeyState(VK_NUMPAD6))
|
|
_ext.jx = g_nu.jx.max;
|
|
|
|
if(GetAsyncKeyState(VK_NUMPAD5)) // y
|
|
_ext.jy = g_nu.jy.min;
|
|
if(GetAsyncKeyState(VK_NUMPAD8))
|
|
_ext.jy = g_nu.jy.max;
|
|
|
|
if(GetAsyncKeyState('C'))
|
|
_ext.bt = 0x01;
|
|
if(GetAsyncKeyState('Z'))
|
|
_ext.bt = 0x02;
|
|
if(GetAsyncKeyState('C') && GetAsyncKeyState('Z'))
|
|
_ext.bt = 0x00;
|
|
#else
|
|
// TODO linux port
|
|
#endif
|
|
|
|
/* 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 = 0x80, Ry = 0x80, Lx = 0x80, Ly = 0x80, lT = 0x80, rT = 0x80;
|
|
|
|
_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()) return;
|
|
// --------------------------------------
|
|
|
|
|
|
// --------------------------------------
|
|
/* Left and right analog sticks
|
|
|
|
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;
|
|
*/
|
|
#ifdef _WIN32
|
|
/* 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 */
|
|
if(GetAsyncKeyState('J')) // left analog left
|
|
Lx = 0x1c;
|
|
if(GetAsyncKeyState('I')) // up
|
|
Ly = 0xe4;
|
|
if(GetAsyncKeyState('L')) // right
|
|
Lx = 0xe4;
|
|
if(GetAsyncKeyState('K')) // down
|
|
Ly = 0x1c;
|
|
|
|
if(GetAsyncKeyState('D')) // right analog left
|
|
Rx = 0x28;
|
|
if(GetAsyncKeyState('R')) // up
|
|
Ry = 0xd8;
|
|
if(GetAsyncKeyState('G')) // right
|
|
Rx = 0xd8;
|
|
if(GetAsyncKeyState('F')) // down
|
|
Ry = 0x28;
|
|
|
|
#endif
|
|
_ext.Lx = (Lx >> 2);
|
|
_ext.Ly = (Ly >> 2);
|
|
_ext.Rx = (Rx >> 3); // this may be wrong
|
|
_ext.Rx2 = (Rx >> 5);
|
|
_ext.Rx3 = (Rx >> 7);
|
|
_ext.Ry = (Ry >> 2);
|
|
|
|
_ext.lT = (Ry >> 2);
|
|
_ext.lT2 = (Ry >> 3);
|
|
_ext.rT = (Ry >> 4);
|
|
// --------------
|
|
#ifdef _WIN32
|
|
|
|
|
|
|
|
// --------------------------------------
|
|
/* D-Pad
|
|
|
|
u8 b1;
|
|
0:
|
|
6: bdD
|
|
7: bdR
|
|
|
|
u8 b2;
|
|
0: bdU
|
|
1: bdL
|
|
*/
|
|
if(GetAsyncKeyState(VK_NUMPAD4)) // left
|
|
_ext.b2.bdL = 0x00;
|
|
|
|
if(GetAsyncKeyState(VK_NUMPAD8)) // up
|
|
_ext.b2.bdU = 0x00;
|
|
|
|
if(GetAsyncKeyState(VK_NUMPAD6)) // right
|
|
_ext.b1.bdR = 0x00;
|
|
|
|
if(GetAsyncKeyState(VK_NUMPAD5)) // down
|
|
_ext.b1.bdD = 0x00;
|
|
// --------------
|
|
|
|
|
|
// --------------------------------------
|
|
/* Buttons
|
|
u8 b1;
|
|
0:
|
|
6: -
|
|
7: -
|
|
|
|
u8 b2;
|
|
0: -
|
|
1: -
|
|
2: bZr
|
|
3: bX
|
|
4: bA
|
|
5: bY
|
|
6: bB
|
|
7: bZl
|
|
*/
|
|
if(GetAsyncKeyState('Z'))
|
|
_ext.b2.bA = 0x00;
|
|
|
|
if(GetAsyncKeyState('C'))
|
|
_ext.b2.bB = 0x00;
|
|
|
|
if(GetAsyncKeyState('Y'))
|
|
_ext.b2.bY = 0x00;
|
|
|
|
if(GetAsyncKeyState('X'))
|
|
_ext.b2.bX = 0x00;
|
|
|
|
if(GetAsyncKeyState('O')) // O instead of P
|
|
_ext.b1.bP = 0x00;
|
|
|
|
if(GetAsyncKeyState('N')) // N instead of M
|
|
_ext.b1.bM = 0x00;
|
|
|
|
if(GetAsyncKeyState('U')) // Home button
|
|
_ext.b1.bH = 0x00;
|
|
|
|
if(GetAsyncKeyState('7')) // digital left trigger
|
|
_ext.b1.bLT = 0x00;
|
|
|
|
if(GetAsyncKeyState('8'))
|
|
_ext.b2.bZL = 0x00;
|
|
|
|
if(GetAsyncKeyState('9'))
|
|
_ext.b2.bZR = 0x00;
|
|
|
|
if(GetAsyncKeyState('0')) // digital right trigger
|
|
_ext.b1.bRT = 0x00;
|
|
|
|
// All buttons pressed
|
|
//if(GetAsyncKeyState('C') && GetAsyncKeyState('Z'))
|
|
// { _ext.b2.bA = 0x01; _ext.b2.bB = 0x01; }
|
|
// --------------
|
|
#else
|
|
// TODO linux port
|
|
#endif
|
|
|
|
/* 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
|