Files
pcsx2/pcsx2/gui/GlobalCommands.cpp
T
2011-04-09 14:53:33 +00:00

595 lines
15 KiB
C++

/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2010 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 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 for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "MainFrame.h"
#include "GSFrame.h"
#include "AppAccelerators.h"
#include "AppSaveStates.h"
#include "Utilities/HashMap.h"
// Various includes needed for dumping...
#include "GS.h"
#include "Dump.h"
#include "DebugTools/Debug.h"
#include "R3000A.h"
using namespace HashTools;
// renderswitch - tells GSdx to go into dx9 sw if "renderswitch" is set.
bool renderswitch = false;
static int g_Pcsx2Recording = 0; // true 1 if recording video and sound
KeyAcceleratorCode::KeyAcceleratorCode( const wxKeyEvent& evt )
{
val32 = 0;
keycode = evt.GetKeyCode();
if( evt.AltDown() ) Alt();
if( evt.CmdDown() ) Cmd();
if( evt.ShiftDown() ) Shift();
}
wxString KeyAcceleratorCode::ToString() const
{
// Let's use wx's string formatter:
return wxAcceleratorEntry(
(cmd ? wxACCEL_CMD : 0) |
(shift ? wxACCEL_CMD : 0) |
(alt ? wxACCEL_CMD : 0),
keycode
).ToString();
}
LimiterModeType g_LimiterMode = Limit_Nominal;
namespace Implementations
{
void Frameskip_Toggle()
{
g_Conf->EmuOptions.GS.FrameSkipEnable = !g_Conf->EmuOptions.GS.FrameSkipEnable;
SetGSConfig().FrameSkipEnable = g_Conf->EmuOptions.GS.FrameSkipEnable;
if( EmuConfig.GS.FrameSkipEnable )
Console.WriteLn( "(FrameSkipping) Enabled : FrameDraws=%d, FrameSkips=%d", g_Conf->EmuOptions.GS.FramesToDraw, g_Conf->EmuOptions.GS.FramesToSkip );
else
Console.WriteLn( "(FrameSkipping) Disabled." );
}
void Framelimiter_TurboToggle()
{
ScopedCoreThreadPause pauser;
if( !g_Conf->EmuOptions.GS.FrameLimitEnable )
{
g_Conf->EmuOptions.GS.FrameLimitEnable = true;
g_LimiterMode = Limit_Turbo;
g_Conf->EmuOptions.GS.LimitScalar = g_Conf->Framerate.TurboScalar;
Console.WriteLn("(FrameLimiter) Turbo + FrameLimit ENABLED." );
if ( g_Conf->Framerate.SkipOnTurbo == true)
g_Conf->EmuOptions.GS.FrameSkipEnable = true;
else
g_Conf->EmuOptions.GS.FrameSkipEnable = false;
}
else if( g_LimiterMode == Limit_Turbo )
{
GSsetVsync( g_Conf->EmuOptions.GS.VsyncEnable );
g_LimiterMode = Limit_Nominal;
g_Conf->EmuOptions.GS.LimitScalar = g_Conf->Framerate.NominalScalar;
if ( g_Conf->Framerate.SkipOnLimit == true)
{
Console.WriteLn("(FrameLimiter) Turbo DISABLED. Frameskip ENABLED" );
g_Conf->EmuOptions.GS.FrameSkipEnable = true;
}
else
{
Console.WriteLn("(FrameLimiter) Turbo DISABLED." );
g_Conf->EmuOptions.GS.FrameSkipEnable = false;
}
}
else
{
GSsetVsync( false );
g_LimiterMode = Limit_Turbo;
g_Conf->EmuOptions.GS.LimitScalar = g_Conf->Framerate.TurboScalar;
if ( g_Conf->Framerate.SkipOnTurbo == true)
{
Console.WriteLn("(FrameLimiter) Turbo + Frameskip ENABLED." );
g_Conf->EmuOptions.GS.FrameSkipEnable = true;
}
else
{
Console.WriteLn("(FrameLimiter) Turbo ENABLED." );
g_Conf->EmuOptions.GS.FrameSkipEnable = false;
}
}
pauser.AllowResume();
}
void Framelimiter_SlomoToggle()
{
// Slow motion auto-enables the framelimiter even if it's disabled.
// This seems like desirable and expected behavior.
// FIXME: Inconsistent use of g_Conf->EmuOptions vs. EmuConfig. Should figure
// out a better consistency approach... -air
ScopedCoreThreadPause pauser;
GSsetVsync( g_Conf->EmuOptions.GS.VsyncEnable );
if( g_LimiterMode == Limit_Slomo )
{
g_LimiterMode = Limit_Nominal;
g_Conf->EmuOptions.GS.LimitScalar = g_Conf->Framerate.NominalScalar;
Console.WriteLn("(FrameLimiter) SlowMotion DISABLED." );
}
else
{
g_LimiterMode = Limit_Slomo;
g_Conf->EmuOptions.GS.LimitScalar = g_Conf->Framerate.SlomoScalar;
Console.WriteLn("(FrameLimiter) SlowMotion ENABLED." );
g_Conf->EmuOptions.GS.FrameLimitEnable = true;
}
pauser.AllowResume();
}
void Framelimiter_MasterToggle()
{
ScopedCoreThreadPause pauser;
g_Conf->EmuOptions.GS.FrameLimitEnable = !g_Conf->EmuOptions.GS.FrameLimitEnable;
GSsetVsync( g_Conf->EmuOptions.GS.FrameLimitEnable && g_Conf->EmuOptions.GS.VsyncEnable );
Console.WriteLn("(FrameLimiter) %s.", g_Conf->EmuOptions.GS.FrameLimitEnable ? "ENABLED" : "DISABLED" );
pauser.AllowResume();
}
void GSwindow_CycleAspectRatio()
{
AspectRatioType& art = g_Conf->GSWindow.AspectRatio;
wxString arts(L"Not modified");
switch( art )
{
case AspectRatio_Stretch: art = AspectRatio_4_3; arts = L"AspectRatio_4_3"; break;
case AspectRatio_4_3: art = AspectRatio_16_9; arts = L"AspectRatio_16:9"; break;
case AspectRatio_16_9: art = AspectRatio_Stretch; arts = L"AspectRatio_Stretch";break;
}
Console.WriteLn(L"(GSwindow) Aspect ratio: %s.", arts.c_str());
AppApplySettings();
}
void UpdateImagePosition()
{
//AppApplySettings() would have been nicer, since it also immidiately affects the GUI (if open).
//However, the events sequence it generates also "depresses" Shift/CTRL/etc, so consecutive zoom with CTRL down breaks.
//Since zoom only affects the window viewport anyway, we can live with directly calling it.
if (GSFrame* gsFrame = wxGetApp().GetGsFramePtr())
if (GSPanel* woot = gsFrame->GetViewport())
woot->DoResize();
}
void SetOffset(float x, float y)
{
g_Conf->GSWindow.OffsetX = x;
g_Conf->GSWindow.OffsetY = y;
Console.WriteLn(L"(GSwindow) Offset: x=%f, y=%f", x,y);
UpdateImagePosition();
}
void GSwindow_OffsetYplus(){
SetOffset(g_Conf->GSWindow.OffsetX.ToFloat(), g_Conf->GSWindow.OffsetY.ToFloat()+1);
}
void GSwindow_OffsetYminus(){
SetOffset(g_Conf->GSWindow.OffsetX.ToFloat(), g_Conf->GSWindow.OffsetY.ToFloat()-1);
}
void GSwindow_OffsetXplus(){
SetOffset(g_Conf->GSWindow.OffsetX.ToFloat()+1, g_Conf->GSWindow.OffsetY.ToFloat());
}
void GSwindow_OffsetXminus(){
SetOffset(g_Conf->GSWindow.OffsetX.ToFloat()-1, g_Conf->GSWindow.OffsetY.ToFloat());
}
void GSwindow_OffsetReset(){
SetOffset(0,0);
}
void SetZoomY(float zoom)
{
if( zoom <= 0 )
return;
g_Conf->GSWindow.StretchY = zoom;
Console.WriteLn(L"(GSwindow) Vertical stretch: %f", zoom);
UpdateImagePosition();
}
void GSwindow_ZoomInY()
{
SetZoomY( g_Conf->GSWindow.StretchY.ToFloat()+1 );
}
void GSwindow_ZoomOutY()
{
SetZoomY( g_Conf->GSWindow.StretchY.ToFloat()-1 );
}
void GSwindow_ZoomResetY()
{
SetZoomY( 100 );
}
void SetZoom(float zoom)
{
if( zoom < 0 )
return;
g_Conf->GSWindow.Zoom = zoom;
if ( zoom == 0 )
Console.WriteLn(L"(GSwindow) Zoom: 0 (auto, no black bars)");
else
Console.WriteLn(L"(GSwindow) Zoom: %f", zoom);
UpdateImagePosition();
}
void GSwindow_ZoomIn()
{
float z = g_Conf->GSWindow.Zoom.ToFloat();
if( z==0 ) z = 100;
z++;
SetZoom( z );
}
void GSwindow_ZoomOut()
{
float z = g_Conf->GSWindow.Zoom.ToFloat();
if( z==0 ) z = 100;
z--;
SetZoom( z );
}
void GSwindow_ZoomToggle()
{
float z = g_Conf->GSWindow.Zoom.ToFloat();
if( z==100 ) z = 0;
else z = 100;
SetZoom( z );
}
void Sys_Suspend()
{
CoreThread.Suspend();
sMainFrame.SetFocus();
}
void Sys_Resume()
{
CoreThread.Resume();
}
void Sys_TakeSnapshot()
{
GSmakeSnapshot( g_Conf->Folders.Snapshots.ToAscii() );
}
void Sys_RenderToggle()
{
ScopedCoreThreadPause paused_core( new SysExecEvent_SaveSinglePlugin(PluginId_GS) );
renderswitch = !renderswitch;
paused_core.AllowResume();
}
void Sys_LoggingToggle()
{
// There's likely a better way to implement this, but this seemed useful.
// I might add turning EE, VU0, and VU1 recs on and off by hotkey at some point, too.
// --arcum42
// FIXME: Some of the trace logs will require recompiler resets to be activated properly.
#ifdef PCSX2_DEVBUILD
SetTraceConfig().Enabled = !EmuConfig.Trace.Enabled;
GSprintf(10, const_cast<char*>(EmuConfig.Trace.Enabled ? "Logging Enabled." : "Logging Disabled."));
#endif
}
void Sys_FreezeGS()
{
// fixme : fix up gsstate mess and make it mtgs compatible -- air
#ifdef _STGS_GSSTATE_CODE
wxString Text;
if( strgametitle[0] != 0 )
{
// only take the first two words
wxString gsText;
wxStringTokenizer parts( strgametitle, L" " );
wxString name( parts.GetNextToken() ); // first part
wxString part2( parts.GetNextToken() );
if( !!part2 )
name += L"_" + part2;
gsText.Printf( L"%s.%d.gs", name.c_str(), StatesC );
Text = Path::Combine( g_Conf->Folders.Savestates, gsText );
}
else
{
Text = GetGSStateFilename();
}
#endif
}
void Sys_RecordingToggle()
{
ScopedCoreThreadPause paused_core;
paused_core.AllowResume();
g_Pcsx2Recording ^= 1;
GetMTGS().WaitGS(); // make sure GS is in sync with the audio stream when we start.
if( GSsetupRecording != NULL ) GSsetupRecording(g_Pcsx2Recording, NULL);
if( SPU2setupRecording != NULL ) SPU2setupRecording(g_Pcsx2Recording, NULL);
}
void Cpu_DumpRegisters()
{
#ifdef PCSX2_DEVBUILD
iDumpRegisters(cpuRegs.pc, 0);
Console.Warning("hardware registers dumped EE:%x, IOP:%x\n", cpuRegs.pc, psxRegs.pc);
#endif
}
void FullscreenToggle()
{
if( GSFrame* gsframe = wxGetApp().GetGsFramePtr() )
gsframe->ShowFullScreen( !gsframe->IsFullScreen() );
}
}
// --------------------------------------------------------------------------------------
// CommandDeclarations table
// --------------------------------------------------------------------------------------
// This is our manualized introspection/reflection table. In a cool language like C# we'd
// have just grabbed this info from enumerating the members of a class and assigning
// properties to each method in the class. But since this is C++, we have to do the the
// goold old fashioned way! :)
static const GlobalCommandDescriptor CommandDeclarations[] =
{
{ "States_FreezeCurrentSlot",
States_FreezeCurrentSlot,
pxL( "Save state" ),
pxL( "Saves the virtual machine state to the current slot." ),
},
{ "States_DefrostCurrentSlot",
States_DefrostCurrentSlot,
pxL( "Load state" ),
pxL( "Loads a virtual machine state from the current slot." ),
},
{ "States_DefrostCurrentSlotBackup",
States_DefrostCurrentSlotBackup,
pxL( "Load State Backup" ),
pxL( "Loads virtual machine state backup for current slot." ),
},
{ "States_CycleSlotForward",
States_CycleSlotForward,
pxL( "Cycle to next slot" ),
pxL( "Cycles the current save slot in +1 fashion!" ),
},
{ "States_CycleSlotBackward",
States_CycleSlotBackward,
pxL( "Cycle to prev slot" ),
pxL( "Cycles the current save slot in -1 fashion!" ),
},
{ "Frameskip_Toggle",
Implementations::Frameskip_Toggle,
NULL,
NULL,
},
{ "Framelimiter_TurboToggle",
Implementations::Framelimiter_TurboToggle,
NULL,
NULL,
},
{ "Framelimiter_SlomoToggle",
Implementations::Framelimiter_SlomoToggle,
NULL,
NULL,
},
{ "Framelimiter_MasterToggle",
Implementations::Framelimiter_MasterToggle,
NULL,
NULL,
},
{ "GSwindow_CycleAspectRatio",
Implementations::GSwindow_CycleAspectRatio,
NULL,
NULL,
},
{ "GSwindow_ZoomIn",
Implementations::GSwindow_ZoomIn,
NULL,
NULL,
},
{ "GSwindow_ZoomOut",
Implementations::GSwindow_ZoomOut,
NULL,
NULL,
},
{ "GSwindow_ZoomToggle",
Implementations::GSwindow_ZoomToggle,
NULL,
NULL,
},
{ "GSwindow_ZoomInY", Implementations::GSwindow_ZoomInY, NULL, NULL, },
{ "GSwindow_ZoomOutY", Implementations::GSwindow_ZoomOutY, NULL, NULL, },
{ "GSwindow_ZoomResetY", Implementations::GSwindow_ZoomResetY, NULL, NULL, },
{ "GSwindow_OffsetYminus", Implementations::GSwindow_OffsetYminus, NULL, NULL, },
{ "GSwindow_OffsetYplus", Implementations::GSwindow_OffsetYplus, NULL, NULL, },
{ "GSwindow_OffsetXminus", Implementations::GSwindow_OffsetXminus, NULL, NULL, },
{ "GSwindow_OffsetXplus", Implementations::GSwindow_OffsetXplus, NULL, NULL, },
{ "GSwindow_OffsetReset", Implementations::GSwindow_OffsetReset, NULL, NULL, },
{ "Sys_Suspend",
Implementations::Sys_Suspend,
NULL,
NULL,
},
{ "Sys_TakeSnapshot",
Implementations::Sys_TakeSnapshot,
NULL,
NULL,
},
{ "Sys_RenderswitchToggle",
Implementations::Sys_RenderToggle,
NULL,
NULL,
},
{ "Sys_LoggingToggle",
Implementations::Sys_LoggingToggle,
NULL,
NULL,
},
{ "Sys_FreezeGS",
Implementations::Sys_FreezeGS,
NULL,
NULL,
},
{ "Sys_RecordingToggle",
Implementations::Sys_RecordingToggle,
NULL,
NULL,
},
{ "FullscreenToggle",
Implementations::FullscreenToggle,
NULL,
NULL,
},
// Command Declarations terminator:
// (must always be last in list!!)
{ NULL }
};
CommandDictionary::CommandDictionary() {}
CommandDictionary::~CommandDictionary() throw() {}
AcceleratorDictionary::AcceleratorDictionary()
: _parent( 0, 0xffffffff )
{
}
AcceleratorDictionary::~AcceleratorDictionary() throw() {}
void AcceleratorDictionary::Map( const KeyAcceleratorCode& acode, const char *searchfor )
{
const GlobalCommandDescriptor* result = NULL;
TryGetValue( acode.val32, result );
if( result != NULL )
{
Console.Warning(
L"Kbd Accelerator '%s' is mapped multiple times.\n"
L"\t'Command %s' is being replaced by '%s'",
acode.ToString().c_str(), fromUTF8( result->Id ).c_str(), fromUTF8( searchfor ).c_str()
);
}
wxGetApp().GlobalCommands->TryGetValue( searchfor, result );
if( result == NULL )
{
Console.Warning( L"Kbd Accelerator '%s' is mapped to unknown command '%s'",
acode.ToString().c_str(), fromUTF8( searchfor ).c_str()
);
}
else
{
operator[](acode.val32) = result;
}
}
void Pcsx2App::BuildCommandHash()
{
if( !GlobalCommands ) GlobalCommands = new CommandDictionary;
const GlobalCommandDescriptor* curcmd = CommandDeclarations;
while( curcmd->Invoke != NULL )
{
(*GlobalCommands)[curcmd->Id] = curcmd;
curcmd++;
}
}
void Pcsx2App::InitDefaultGlobalAccelerators()
{
typedef KeyAcceleratorCode AAC;
if( !GlobalAccels ) GlobalAccels = new AcceleratorDictionary;
GlobalAccels->Map( AAC( WXK_F1 ), "States_FreezeCurrentSlot" );
GlobalAccels->Map( AAC( WXK_F3 ), "States_DefrostCurrentSlot" );
GlobalAccels->Map( AAC( WXK_F2 ), "States_CycleSlotForward" );
GlobalAccels->Map( AAC( WXK_F2 ).Shift(), "States_CycleSlotBackward" );
GlobalAccels->Map( AAC( WXK_F4 ), "Framelimiter_MasterToggle");
GlobalAccels->Map( AAC( WXK_F4 ).Shift(), "Frameskip_Toggle");
/*GlobalAccels->Map( AAC( WXK_ESCAPE ), "Sys_Suspend");
GlobalAccels->Map( AAC( WXK_F8 ), "Sys_TakeSnapshot");
GlobalAccels->Map( AAC( WXK_F8 ).Shift(), "Sys_TakeSnapshot");
GlobalAccels->Map( AAC( WXK_F8 ).Shift().Cmd(),"Sys_TakeSnapshot");
GlobalAccels->Map( AAC( WXK_F9 ), "Sys_RenderswitchToggle");
GlobalAccels->Map( AAC( WXK_F10 ), "Sys_LoggingToggle");
GlobalAccels->Map( AAC( WXK_F11 ), "Sys_FreezeGS");
GlobalAccels->Map( AAC( WXK_F12 ), "Sys_RecordingToggle");
GlobalAccels->Map( AAC( WXK_RETURN ).Alt(), "FullscreenToggle" );*/
}