mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-01-25 23:41:19 +01:00
f6d844dac1
Wiimotes are now slighty more responsive and multiple wiimotes should harmonize now slighty better. This clean up was requested/inevitable and should have be done way more earlier. This "might" break osx/linux builds, so please test. If your aware of any "real wiimote" issues please post it in the comments as well(dont forget to state your OS). Known wiimote issues: 1.) Possible wiimote disconnect on pressing the home button 2.) 1-2 Possible wiimote disconnects directly after starting a game 3.) Rumble causes lag. I don't think this is a wiimote plugin issue itself, I'm not sure tho. It would be interesting to know whether the lag still happens on emulated wiimotes as well, when the game tries to rumble. 4.) Connecting(pairing up and refreshing) a 2nd/3rd/4th real wiimote while having a game running/paused, might swap player slots and cause disconnects at that moment. If u have more issues, feel free to post them, to have them all here collected once more to get a brief overview. Apart from that, increase the wiimote read timeout @settings(20-200). If your expecting frequent disconnects, restart dolphin, and don't open the wiimote gui before playing instead directly start games. git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@5788 8ced0084-cf51-0410-be5f-012b33b47a6e
424 lines
11 KiB
C++
424 lines
11 KiB
C++
// Copyright (C) 2003 Dolphin Project.
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, version 2.0.
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License 2.0 for more details.
|
|
|
|
// A copy of the GPL 2.0 should have been included with the program.
|
|
// If not, see http://www.gnu.org/licenses/
|
|
|
|
// Official SVN repository and contact information can be found at
|
|
// http://code.google.com/p/dolphin-emu/
|
|
|
|
|
|
#include "Common.h" // Common
|
|
#include "LogManager.h"
|
|
#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"
|
|
#if defined(HAVE_WX) && HAVE_WX
|
|
#include "ConfigPadDlg.h"
|
|
#include "ConfigBasicDlg.h"
|
|
|
|
WiimotePadConfigDialog *m_PadConfigFrame = NULL;
|
|
WiimoteBasicConfigDialog *m_BasicConfigFrame = NULL;
|
|
#endif
|
|
#include "Config.h"
|
|
#include "pluginspecs_wiimote.h"
|
|
#include "EmuMain.h"
|
|
#if HAVE_WIIUSE
|
|
#include "wiimote_real.h"
|
|
#endif
|
|
|
|
#if defined(HAVE_X11) && HAVE_X11
|
|
Display* WMdisplay;
|
|
#endif
|
|
SWiimoteInitialize g_WiimoteInitialize;
|
|
PLUGIN_GLOBALS* globals = NULL;
|
|
|
|
// General
|
|
bool g_EmulatorRunning = false;
|
|
u32 g_ISOId = 0;
|
|
bool g_SearchDeviceDone = false;
|
|
bool g_RealWiiMotePresent = false;
|
|
|
|
// Debugging
|
|
bool g_DebugAccelerometer = false;
|
|
bool g_DebugData = false;
|
|
bool g_DebugComm = false;
|
|
bool g_DebugSoundData = false;
|
|
bool g_DebugCustom = 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);
|
|
|
|
PLUGIN_EMUSTATE g_EmulatorState = PLUGIN_EMUSTATE_STOP;
|
|
|
|
// Standard crap to make wxWidgets happy
|
|
#ifdef _WIN32
|
|
HINSTANCE g_hInstance;
|
|
|
|
#if defined(HAVE_WX) && HAVE_WX
|
|
class wxDLLApp : public wxApp
|
|
{
|
|
bool OnInit()
|
|
{
|
|
return true;
|
|
}
|
|
};
|
|
IMPLEMENT_APP_NO_MAIN(wxDLLApp)
|
|
WXDLLIMPEXP_BASE void wxSetInstance(HINSTANCE hInst);
|
|
#endif
|
|
|
|
BOOL APIENTRY DllMain(HINSTANCE hinstDLL, // DLL module handle
|
|
DWORD dwReason, // reason called
|
|
LPVOID lpvReserved) // reserved
|
|
{
|
|
switch (dwReason)
|
|
{
|
|
case DLL_PROCESS_ATTACH:
|
|
{
|
|
#if defined(HAVE_WX) && HAVE_WX
|
|
wxSetInstance((HINSTANCE)hinstDLL);
|
|
wxInitialize();
|
|
#endif
|
|
}
|
|
break;
|
|
|
|
case DLL_PROCESS_DETACH:
|
|
{
|
|
#if defined(HAVE_WX) && HAVE_WX
|
|
wxUninitialize();
|
|
#endif
|
|
}
|
|
break;
|
|
}
|
|
|
|
g_hInstance = hinstDLL;
|
|
return TRUE;
|
|
}
|
|
#endif
|
|
|
|
#if defined(HAVE_WX) && HAVE_WX
|
|
wxWindow* GetParentedWxWindow(HWND Parent)
|
|
{
|
|
#ifdef _WIN32
|
|
wxSetInstance((HINSTANCE)g_hInstance);
|
|
#endif
|
|
wxWindow *win = new wxWindow();
|
|
#ifdef _WIN32
|
|
win->SetHWND((WXHWND)Parent);
|
|
win->AdoptAttributesFromHWND();
|
|
#endif
|
|
return win;
|
|
}
|
|
#endif
|
|
|
|
// Exports
|
|
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)
|
|
{
|
|
#ifdef _WIN32
|
|
if (WiiMoteReal::g_AutoPairUpInvisibleWindow == NULL)
|
|
{
|
|
WiiMoteReal::g_AutoPairUpInvisibleWindow = new Common::Thread(WiiMoteReal::RunInvisibleMessageWindow_ThreadFunc, NULL);
|
|
WiiMoteReal::g_AutoPairUpMonitoring = new Common::Thread(WiiMoteReal::PairUp_ThreadFunc, NULL);
|
|
}
|
|
#endif
|
|
if (!g_SearchDeviceDone)
|
|
{
|
|
// Load settings
|
|
g_Config.Load();
|
|
// We do a pad search before creating the dialog
|
|
WiiMoteEmu::Search_Devices(WiiMoteEmu::joyinfo, WiiMoteEmu::NumPads, WiiMoteEmu::NumGoodPads);
|
|
g_SearchDeviceDone = true;
|
|
}
|
|
|
|
|
|
#if defined(HAVE_WX) && HAVE_WX
|
|
wxWindow *frame = GetParentedWxWindow(_hParent);
|
|
m_BasicConfigFrame = new WiimoteBasicConfigDialog(frame);
|
|
#ifdef _WIN32
|
|
frame->Disable();
|
|
m_BasicConfigFrame->ShowModal();
|
|
frame->Enable();
|
|
#else
|
|
m_BasicConfigFrame->ShowModal();
|
|
#endif
|
|
|
|
#ifdef _WIN32
|
|
frame->SetFocus();
|
|
frame->SetHWND(NULL);
|
|
#endif
|
|
|
|
m_BasicConfigFrame->Destroy();
|
|
m_BasicConfigFrame = NULL;
|
|
frame->Destroy();
|
|
#endif
|
|
}
|
|
|
|
// Start emulation
|
|
void Initialize(void *init)
|
|
{
|
|
g_EmulatorRunning = true;
|
|
g_WiimoteInitialize = *(SWiimoteInitialize *)init;
|
|
|
|
#if defined(HAVE_WX) && HAVE_WX
|
|
// Load the ISO Id
|
|
g_ISOId = g_WiimoteInitialize.ISOId;
|
|
// Load the settings
|
|
g_Config.Load();
|
|
#endif
|
|
#if defined(HAVE_X11) && HAVE_X11
|
|
WMdisplay = (Display*)g_WiimoteInitialize.hWnd;
|
|
#endif
|
|
|
|
g_ISOId = g_WiimoteInitialize.ISOId;
|
|
DEBUG_LOG(WIIMOTE, "ISOId: %08x %s", g_WiimoteInitialize.ISOId, Hex2Ascii(g_WiimoteInitialize.ISOId).c_str());
|
|
|
|
// Load IR settings, as this is a per-game setting and the user might have loaded a different game
|
|
g_Config.LoadIR();
|
|
|
|
// 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
|
|
|
|
WiiMoteReal::Initialize();
|
|
WiiMoteReal::Allocate();
|
|
#ifdef _WIN32
|
|
if (WiiMoteReal::g_AutoPairUpInvisibleWindow == NULL)
|
|
{
|
|
WiiMoteReal::g_AutoPairUpInvisibleWindow = new Common::Thread(WiiMoteReal::RunInvisibleMessageWindow_ThreadFunc, NULL);
|
|
WiiMoteReal::g_AutoPairUpMonitoring = new Common::Thread(WiiMoteReal::PairUp_ThreadFunc, NULL);
|
|
}
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
// If a game is not running this is called by the Configuration window when it's closed
|
|
void Shutdown(void)
|
|
{
|
|
// Not running
|
|
g_EmulatorRunning = false;
|
|
|
|
// Reset the game ID in all cases
|
|
g_ISOId = 0;
|
|
|
|
#if HAVE_WIIUSE
|
|
WiiMoteReal::Shutdown();
|
|
#endif
|
|
WiiMoteEmu::Shutdown();
|
|
}
|
|
|
|
|
|
void DoState(unsigned char **ptr, int mode)
|
|
{
|
|
PointerWrap p(ptr, mode);
|
|
|
|
// TODO: Shorten the list
|
|
|
|
//p.Do(g_EmulatorRunning);
|
|
//p.Do(g_ISOId);
|
|
//p.Do(g_RealWiiMotePresent);
|
|
//p.Do(g_RealWiiMoteInitialized);
|
|
//p.Do(g_EmulatedWiiMoteInitialized);
|
|
//p.Do(g_UpdateCounter);
|
|
//p.Do(g_UpdateTime);
|
|
//p.Do(g_UpdateRate);
|
|
//p.Do(g_UpdateWriteScreen);
|
|
//p.Do(g_UpdateTimeList);
|
|
|
|
#if HAVE_WIIUSE
|
|
WiiMoteReal::DoState(p);
|
|
#endif
|
|
WiiMoteEmu::DoState(p);
|
|
|
|
return;
|
|
}
|
|
void EmuStateChange(PLUGIN_EMUSTATE newState)
|
|
{
|
|
g_EmulatorState = newState;
|
|
}
|
|
|
|
#if defined(HAVE_WX) && HAVE_WX
|
|
// Hack to use wx key events
|
|
volatile bool wxkeystate[WXK_SPECIAL20];
|
|
#endif
|
|
|
|
// Set buttons status from keyboard input. Currently this is done from
|
|
// wxWidgets in the main application.
|
|
// --------------
|
|
void Wiimote_Input(u16 _Key, u8 _UpDown)
|
|
{
|
|
#if defined(__APPLE__) && defined(USE_WX) && USE_WX
|
|
if (_Key < WXK_SPECIAL20)
|
|
{
|
|
wxkeystate[_Key] = _UpDown;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/* 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.
|
|
*/
|
|
void Wiimote_InterruptChannel(int _number, u16 _channelID, const void* _pData, u32 _Size)
|
|
{
|
|
// Decide where to send the message
|
|
if (WiiMoteEmu::WiiMapping[_number].Source <= 1)
|
|
WiiMoteEmu::InterruptChannel(_number, _channelID, _pData, _Size);
|
|
#if HAVE_WIIUSE
|
|
else if (g_RealWiiMotePresent)
|
|
WiiMoteReal::InterruptChannel(_number, _channelID, _pData, _Size);
|
|
#endif
|
|
}
|
|
|
|
|
|
// Function: Used for the initial Bluetooth HID handshake.
|
|
void Wiimote_ControlChannel(int _number, u16 _channelID, const void* _pData, u32 _Size)
|
|
{
|
|
// Debugging
|
|
#if defined(_DEBUG) || defined(DEBUGFAST)
|
|
DEBUG_LOG(WIIMOTE, "Wiimote_ControlChannel");
|
|
DEBUG_LOG(WIIMOTE, " Channel ID: %04x", _channelID);
|
|
std::string Temp = ArrayToString((const u8*)_pData, _Size);
|
|
DEBUG_LOG(WIIMOTE, " Data: %s", Temp.c_str());
|
|
#endif
|
|
|
|
// Check for custom communication
|
|
if(_channelID == 99 && *(const u8*)_pData == WIIMOTE_DISCONNECT)
|
|
{
|
|
WiiMoteEmu::g_ReportingAuto[_number] = false;
|
|
WARN_LOG(WIIMOTE, "Wiimote: #%i Disconnected", _number);
|
|
#ifdef _WIN32
|
|
PostMessage(g_WiimoteInitialize.hWnd, WM_USER, WIIMOTE_DISCONNECT, _number);
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
if (WiiMoteEmu::WiiMapping[_number].Source <= 1)
|
|
WiiMoteEmu::ControlChannel(_number, _channelID, _pData, _Size);
|
|
#if HAVE_WIIUSE
|
|
else if (g_RealWiiMotePresent)
|
|
WiiMoteReal::ControlChannel(_number, _channelID, _pData, _Size);
|
|
#endif
|
|
}
|
|
|
|
|
|
// This sends a Data Report from the Wiimote. See SystemTimers.cpp for the documentation of this update.
|
|
void Wiimote_Update(int _number)
|
|
{
|
|
// This functions will send:
|
|
// Emulated Wiimote: Only data reports 0x30-0x37
|
|
// Real Wiimote: Both data reports 0x30-0x37 and all other read reports
|
|
if (WiiMoteEmu::WiiMapping[_number].Source <= 1)
|
|
WiiMoteEmu::Update(_number);
|
|
#if HAVE_WIIUSE
|
|
else if (g_RealWiiMotePresent)
|
|
WiiMoteReal::Update(_number);
|
|
#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; DEBUG_LOG(WIIMOTE, "Custom Debug: Off");} // End
|
|
else if (GetAsyncKeyState(VK_END) && !g_DebugCustom ) {g_DebugCustom = true; DEBUG_LOG(WIIMOTE, "Custom Debug: Off");}
|
|
#endif
|
|
*/
|
|
|
|
}
|
|
|
|
unsigned int Wiimote_GetAttachedControllers()
|
|
{
|
|
unsigned int attached = 0;
|
|
for (unsigned int i=0; i<4; ++i)
|
|
if (WiiMoteEmu::WiiMapping[i].Source)
|
|
attached |= (1 << i);
|
|
return attached;
|
|
}
|
|
|
|
|
|
// Unpair Wiimotes, TODO: Add linux/osx un-pair function
|
|
unsigned int Wiimote_UnPairWiimotes()
|
|
{
|
|
#ifdef _WIN32
|
|
if (g_Config.bUnpairRealWiimote)
|
|
return WiiMoteReal::WiimotePairUp(true);
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
// Supporting functions
|
|
|
|
// Check if the render window is in focus
|
|
|
|
bool IsFocus()
|
|
{
|
|
#if defined(__APPLE__) && defined(USE_WX) && USE_WX
|
|
return true; /* XXX */
|
|
#endif
|
|
return g_WiimoteInitialize.pRendererHasFocus();
|
|
}
|
|
|
|
/* 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. */
|
|
// -----------------
|