27 Commits

Author SHA1 Message Date
Glenn Rice 88156cff05 Link wiiuse statically in linux.
Fixes issue 2562


git-svn-id: https://dolphin-emu.googlecode.com/svn/branches/stable@5384 8ced0084-cf51-0410-be5f-012b33b47a6e
2010-04-18 14:50:21 +00:00
Glenn Rice 1b7065d8b4 Change the textctrl->SetLabel's to textctrl->SetValue's in stable too.
git-svn-id: https://dolphin-emu.googlecode.com/svn/branches/stable@5369 8ced0084-cf51-0410-be5f-012b33b47a6e
2010-04-14 23:39:36 +00:00
Glenn Rice 909f36017b Fixed segfault in linux when the control chooser dialog of GCPadNew is closed.
Also disabled some code in the same place that caused the application to hang in linux.  This means that if you select keys from the key list you will have to click Set to make it take effect.  At least until I can figure out how to get that working.


git-svn-id: https://dolphin-emu.googlecode.com/svn/branches/stable@5368 8ced0084-cf51-0410-be5f-012b33b47a6e
2010-04-14 20:29:46 +00:00
Shawn Hoffman 631df2d903 stable: ensure SubWCRev.exe doesn't run...heh
git-svn-id: https://dolphin-emu.googlecode.com/svn/branches/stable@5350 8ced0084-cf51-0410-be5f-012b33b47a6e
2010-04-13 00:52:51 +00:00
Glenn Rice 789045e1b2 Make sure Keyboard::Key::GetState returns either 0 or 1 in linux to make sure key presses are registered.
git-svn-id: https://dolphin-emu.googlecode.com/svn/branches/stable@5325 8ced0084-cf51-0410-be5f-012b33b47a6e
2010-04-10 22:49:57 +00:00
Glenn Rice 19551fb864 Set GCPadNew as the default in linux. By request of nakeee!
git-svn-id: https://dolphin-emu.googlecode.com/svn/branches/stable@5324 8ced0084-cf51-0410-be5f-012b33b47a6e
2010-04-10 22:29:38 +00:00
Glenn Rice 449e28f9a6 Add linux fixes to GCPadNew from trunk.
git-svn-id: https://dolphin-emu.googlecode.com/svn/branches/stable@5323 8ced0084-cf51-0410-be5f-012b33b47a6e
2010-04-10 21:56:12 +00:00
Shawn Hoffman 45db281360 stable: nogui buildfix
git-svn-id: https://dolphin-emu.googlecode.com/svn/branches/stable@5322 8ced0084-cf51-0410-be5f-012b33b47a6e
2010-04-10 21:36:10 +00:00
Jordan Woyak cb38303531 stable: Applied the same fixes/cleanups to GCPadNew.cpp as the last commit by glennrics.
git-svn-id: https://dolphin-emu.googlecode.com/svn/branches/stable@5299 8ced0084-cf51-0410-be5f-012b33b47a6e
2010-04-08 22:47:58 +00:00
nakeee 1310052bd7 Stable: wiimote fix and memarena fix from trunk
git-svn-id: https://dolphin-emu.googlecode.com/svn/branches/stable@5295 8ced0084-cf51-0410-be5f-012b33b47a6e
2010-04-08 13:50:20 +00:00
nakeee 9d786b6440 Stable: another small HLE fix
git-svn-id: https://dolphin-emu.googlecode.com/svn/branches/stable@5294 8ced0084-cf51-0410-be5f-012b33b47a6e
2010-04-08 13:41:35 +00:00
nakeee 9734e39530 Stable:
Changed version to 2.0
Backported HLE changed from trunk


git-svn-id: https://dolphin-emu.googlecode.com/svn/branches/stable@5293 8ced0084-cf51-0410-be5f-012b33b47a6e
2010-04-08 13:32:09 +00:00
Jordan Woyak ed4318b949 stable: Added GCPadNew Plugin. Set it to default on windows.
git-svn-id: https://dolphin-emu.googlecode.com/svn/branches/stable@5291 8ced0084-cf51-0410-be5f-012b33b47a6e
2010-04-08 05:39:52 +00:00
Shawn Hoffman 21a240547e stable: Don't enable selection of mic device if dolphin is not compiled with portaudio support.
Restrict SI AM Baseboard device to port 1.

git-svn-id: https://dolphin-emu.googlecode.com/svn/branches/stable@5279 8ced0084-cf51-0410-be5f-012b33b47a6e
2010-04-04 19:26:10 +00:00
NeoBrainX cfd83be9a1 stable: Apply JIT/Int fixes from stable.
Fixes shadows in Animal Crossing and Matter Splatter Galaxy in SMG.
(fixes by godisgovernment and possibly others)


git-svn-id: https://dolphin-emu.googlecode.com/svn/branches/stable@5276 8ced0084-cf51-0410-be5f-012b33b47a6e
2010-04-04 18:14:37 +00:00
j4ck.fr0st 620c263582 stable: Fix game-specific dual-core checkbox, include the fix for scons bundle
git-svn-id: https://dolphin-emu.googlecode.com/svn/branches/stable@5257 8ced0084-cf51-0410-be5f-012b33b47a6e
2010-03-31 16:41:45 +00:00
Sonicadvance1 559bfa3112 Put my JIT fixes in stable
git-svn-id: https://dolphin-emu.googlecode.com/svn/branches/stable@5214 8ced0084-cf51-0410-be5f-012b33b47a6e
2010-03-18 17:58:33 +00:00
Glenn Rice dff7aa5ed6 Same as my last trunk commit.
git-svn-id: https://dolphin-emu.googlecode.com/svn/branches/stable@5210 8ced0084-cf51-0410-be5f-012b33b47a6e
2010-03-17 18:59:24 +00:00
Glenn Rice 8d826b4f62 Backport of my recent changes to fullscreen and render to main in linux, and some of my other little bug fixes.
Also backported godisgovernment's removal of wiimote led and speaker status.  I hope this is okay with you.


git-svn-id: https://dolphin-emu.googlecode.com/svn/branches/stable@5208 8ced0084-cf51-0410-be5f-012b33b47a6e
2010-03-17 13:06:10 +00:00
j4ck.fr0st f77140336d reverted the svnrev.h change, removed revision generation from scons (linux and osx should also get RC1 now instead of the revision number)
git-svn-id: https://dolphin-emu.googlecode.com/svn/branches/stable@5198 8ced0084-cf51-0410-be5f-012b33b47a6e
2010-03-15 17:53:42 +00:00
Glenn Rice 29cb2ddd87 Add shared library scons options to stable tree.
git-svn-id: https://dolphin-emu.googlecode.com/svn/branches/stable@5197 8ced0084-cf51-0410-be5f-012b33b47a6e
2010-03-15 12:23:19 +00:00
skidau 88af328437 Merged r5172 to stable branch.
(Added a null check when stopping the DSPHLE plugin with the DSound back-end.  Fixes the DSPHLE crash on stop.)

git-svn-id: https://dolphin-emu.googlecode.com/svn/branches/stable@5173 8ced0084-cf51-0410-be5f-012b33b47a6e
2010-03-08 08:16:08 +00:00
Shawn Hoffman 318abc4ece stable: remove the svn:ignore on svnrev.h
git-svn-id: https://dolphin-emu.googlecode.com/svn/branches/stable@5171 8ced0084-cf51-0410-be5f-012b33b47a6e
2010-03-08 00:22:06 +00:00
Shawn Hoffman d4ba991dd3 should fix wii homebrew (loading) on osx. can't test atm though...
git-svn-id: https://dolphin-emu.googlecode.com/svn/branches/stable@5169 8ced0084-cf51-0410-be5f-012b33b47a6e
2010-03-07 19:23:47 +00:00
Shawn Hoffman 9ea17949ef addendum to last commit: need static svnrev.h for stable build
git-svn-id: https://dolphin-emu.googlecode.com/svn/branches/stable@5168 8ced0084-cf51-0410-be5f-012b33b47a6e
2010-03-07 19:16:17 +00:00
Shawn Hoffman fc74ce36c6 stable: mark as "2.0 RC1"
git-svn-id: https://dolphin-emu.googlecode.com/svn/branches/stable@5167 8ced0084-cf51-0410-be5f-012b33b47a6e
2010-03-07 19:13:44 +00:00
hrydgard d42a27937d Branch off Stable, since Dolphin is in a pretty good state. This branch will become the official release we'll do shortly.
This opens up the trunk for more experimental coding work again.

Nakee, I appoint you Release Manager :)

git-svn-id: https://dolphin-emu.googlecode.com/svn/branches/stable@5164 8ced0084-cf51-0410-be5f-012b33b47a6e
2010-03-06 11:33:51 +00:00
96 changed files with 7202 additions and 1225 deletions
+1 -1
View File
@@ -10,4 +10,4 @@ env_lzo = env.Clone(
CCFLAGS = env.filterWarnings(env['CCFLAGS']),
CXXFLAGS = env.filterWarnings(env['CXXFLAGS']),
)
env_lzo.StaticLibrary(env['local_libs'] + "minilzo", files)
env_lzo.StaticLibrary(env['local_libs'] + "lzo2", files)
+1 -1
View File
@@ -19,4 +19,4 @@ env_sfml = env.Clone(
CXXFLAGS = env.filterWarnings(env['CXXFLAGS']),
)
env_sfml.StaticLibrary(env['local_libs'] + "sfml", files)
env_sfml.StaticLibrary(env['local_libs'] + "sfml-network", files)
+1 -1
View File
@@ -15,4 +15,4 @@ env_soil = env.Clone(
parse_flags = ['-fPIC']
)
env_soil.StaticLibrary(env['local_libs'] + "libsoil", files)
env_soil.StaticLibrary(env['local_libs'] + "SOIL", files)
+2 -4
View File
@@ -34,15 +34,13 @@ else:
env_wiiuse = env.Clone(
CCFLAGS = env.filterWarnings(env['CCFLAGS']) + ' -fvisibility=default',
CXXFLAGS = env.filterWarnings(env['CXXFLAGS']),
parse_flags = ['-fPIC']
)
libs = [
'm',
]
if sys.platform == 'darwin':
env_wiiuse.StaticLibrary(env['libs_dir']+"wiiuse", files, LIBS=libs)
else:
env_wiiuse.SharedLibrary(env['libs_dir']+"wiiuse", files, LIBS=libs)
env_wiiuse.StaticLibrary(env['libs_dir']+"wiiuse", files, LIBS=libs)
env['HAVE_WIIUSE'] = 1
+51 -13
View File
@@ -50,10 +50,7 @@ include_paths = [
basedir + 'Source/Core/Core/Src',
basedir + 'Source/Core/DebuggerWX/Src',
basedir + 'Externals/Bochs_disasm',
basedir + 'Externals/LZO',
basedir + 'Externals/SOIL',
basedir + 'Externals/Lua',
basedir + 'Externals/SFML/include',
basedir + 'Externals/WiiUseSrc/Src',
basedir + 'Source/Core/VideoCommon/Src',
basedir + 'Source/Core/InputCommon/Src',
@@ -64,9 +61,6 @@ include_paths = [
dirs = [
'Externals/Bochs_disasm',
'Externals/LZO',
'Externals/SOIL',
'Externals/SFML/src',
'Externals/Lua',
'Externals/WiiUseSrc/Src',
'Source/Core/Common/Src',
@@ -83,6 +77,7 @@ dirs = [
'Source/Plugins/Plugin_DSP_HLE/Src',
'Source/Plugins/Plugin_DSP_LLE/Src',
'Source/Plugins/Plugin_GCPad/Src',
'Source/Plugins/Plugin_GCPadNew/Src',
'Source/Plugins/Plugin_Wiimote/Src',
'Source/Core/DolphinWX/Src',
'Source/Core/DebuggerWX/Src',
@@ -112,6 +107,9 @@ vars.AddVariables(
BoolVariable('wxgl', 'Set For Building with WX GL libs (WIP)', False),
BoolVariable('opencl', 'Build with OpenCL', False),
BoolVariable('nojit', 'Remove entire jit cores', False),
BoolVariable('shared_soil', 'Use system shared libSOIL', False),
BoolVariable('shared_lzo', 'Use system shared liblzo2', False),
BoolVariable('shared_sfml', 'Use system shared libsfml-network', False),
PathVariable('userdir', 'Set the name of the user data directory in home', '.dolphin-emu', PathVariable.PathAccept),
EnumVariable('install', 'Choose a local or global installation', 'local',
allowed_values = ('local', 'global'),
@@ -188,7 +186,7 @@ if not env['verbose']:
env['RANLIBCOMSTR'] = "Indexing $TARGET"
# build flavor
flavour = ARGUMENTS.get('flavor')
flavour = env['flavor']
if (flavour == 'debug'):
compileFlags.append('-ggdb')
cppDefines.append('_DEBUG') #enables LOGGING
@@ -257,7 +255,7 @@ elif flavour == 'prof':
extra = '-prof'
# Set up the install locations
if (ARGUMENTS.get('install') == 'global'):
if (env['install'] == 'global'):
env['prefix'] = os.path.join(env['prefix'] + os.sep)
env['binary_dir'] = env['prefix'] + 'bin/'
env['libs_dir'] = env['prefix'] + 'lib/'
@@ -324,6 +322,40 @@ if sys.platform != 'darwin':
# needed for mic
env['HAVE_PORTAUDIO'] = conf.CheckPortaudio(1890)
# SOIL
env['SHARED_SOIL'] = 0;
if env['shared_soil']:
env['SHARED_SOIL'] = conf.CheckPKG('SOIL')
if not env['SHARED_SOIL']:
print "shared SOIL library not detected"
print "falling back to the static library"
if not env['SHARED_SOIL']:
env['CPPPATH'] += [ basedir + 'Externals/SOIL' ]
dirs += ['Externals/SOIL']
# LZO
env['SHARED_LZO'] = 0;
if env['shared_lzo']:
env['SHARED_LZO'] = conf.CheckPKG('lzo2')
if not env['SHARED_LZO']:
print "shared LZO library not detected"
print "falling back to the static library"
if not env['SHARED_LZO']:
env['CPPPATH'] += [ basedir + 'Externals/LZO' ]
dirs += ['Externals/LZO']
# SFML
env['SHARED_SFML'] = 0;
if env['shared_sfml']:
# TODO: Check the version of sfml. It should be at least version 1.5
env['SHARED_SFML'] = conf.CheckPKG('sfml-network') and conf.CheckCXXHeader("SFML/Network/Ftp.hpp")
if not env['SHARED_SFML']:
print "shared sfml-network library not detected"
print "falling back to the static library"
if not env['SHARED_SFML']:
env['CPPPATH'] += [ basedir + 'Externals/SFML/include' ]
dirs += ['Externals/SFML/src']
#osx 64 specifics
if sys.platform == 'darwin':
if env['osx'] == '64cocoa':
@@ -380,8 +412,11 @@ conf.Define('USE_WX', env['USE_WX'])
conf.Define('HAVE_X11', env['HAVE_X11'])
conf.Define('HAVE_COCOA', env['HAVE_COCOA'])
conf.Define('HAVE_PORTAUDIO', env['HAVE_PORTAUDIO'])
conf.Define('SHARED_SOIL', env['SHARED_SOIL'])
conf.Define('SHARED_LZO', env['SHARED_LZO'])
conf.Define('SHARED_SFML', env['SHARED_SFML'])
conf.Define('USER_DIR', "\"" + env['userdir'] + "\"")
if (ARGUMENTS.get('install') == 'global'):
if (env['install'] == 'global'):
conf.Define('DATA_DIR', "\"" + env['data_dir'] + "\"")
conf.Define('LIBS_DIR', "\"" + env['libs_dir'] + "\"")
@@ -434,9 +469,6 @@ else:
# add methods from utils to env
env.AddMethod(utils.filterWarnings)
rev = utils.GenerateRevFile(env['flavor'],
"Source/Core/Common/Src/svnrev_template.h",
"Source/Core/Common/Src/svnrev.h")
# print a nice progress indication when not compiling
Progress(['-\r', '\\\r', '|\r', '/\r'], interval = 5)
@@ -481,9 +513,15 @@ else:
env.Alias('install', env['prefix'])
if env['bundle']:
# get the rev anyways, RC != RC between commits
# copied from utils.py, could be solved better...
try:
rev = os.popen('svnversion .').read().strip().split(':')[0]
except:
rev = ""
# Make tar ball (TODO put inside normal dir)
tar_env = env.Clone()
tarball = tar_env.Tar('dolphin-'+rev +'.tar.bz2', env['prefix'])
tarball = tar_env.Tar('dolphin-2.0.tar.bz2', env['prefix'])
tar_env.Append(TARFLAGS='-j',
TARCOMSTR="Creating release tarball")
+2 -1
View File
@@ -162,7 +162,8 @@ void DSound::Clear(bool mute)
if (m_muted)
{
dsBuffer->Stop();
if (dsBuffer != NULL)
dsBuffer->Stop();
}
else
{
+1
View File
@@ -85,6 +85,7 @@
#define HAVE_WX 1
#define HAVE_OPENAL 1
#define HAVE_ALSA 0
#define HAVE_PORTAUDIO 0
// it is VERY DANGEROUS to mix _SECURE_SCL=0 and _SECURE_SCL=1 compiled libraries.
// You will get bizarre crash bugs whenever you use STL.
+4
View File
@@ -129,7 +129,11 @@
// Plugin files
#define DEFAULT_GFX_PLUGIN PLUGIN_PREFIX "Plugin_VideoOGL" PLUGIN_SUFFIX
#define DEFAULT_DSP_PLUGIN PLUGIN_PREFIX "Plugin_DSP_HLE" PLUGIN_SUFFIX
#if defined(_WIN32) || defined(__linux__)
#define DEFAULT_PAD_PLUGIN PLUGIN_PREFIX "Plugin_GCPadNew" PLUGIN_SUFFIX
#else
#define DEFAULT_PAD_PLUGIN PLUGIN_PREFIX "Plugin_GCPad" PLUGIN_SUFFIX
#endif
#define DEFAULT_WIIMOTE_PLUGIN PLUGIN_PREFIX "Plugin_Wiimote" PLUGIN_SUFFIX
// Sys files
+1 -1
View File
@@ -40,7 +40,7 @@ static const char* ram_temp_file = "/tmp/gc_mem.tmp";
void MemArena::GrabLowMemSpace(size_t size)
{
#ifdef _WIN32
hMemoryMapping = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, (DWORD)(size), _T("All GC Memory"));
hMemoryMapping = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, (DWORD)(size), NULL);
#else
mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
fd = open(ram_temp_file, O_RDWR | O_CREAT, mode);
+2
View File
@@ -0,0 +1,2 @@
#define SVN_REV 5163
#define SVN_REV_STR "2.0"
Binary file not shown.
+1 -1
View File
@@ -198,7 +198,7 @@ bool CBoot::SetupWiiMemory(unsigned int _CountryCode)
default:
// PanicAlert("SetupWiiMem: Unknown country. Wii boot process will be switched to European settings.");
filename = WII_EUR_SETTING_FILE;
filename = File::GetSysDirectory() + WII_SYS_DIR + DIR_SEP + WII_EUR_SETTING;
break;
}
-4
View File
@@ -85,8 +85,6 @@ void SConfig::SaveSettings()
ini.Set("Interface", "MainWindowPosY", m_LocalCoreStartupParameter.iPosY);
ini.Set("Interface", "MainWindowWidth", m_LocalCoreStartupParameter.iWidth);
ini.Set("Interface", "MainWindowHeight", m_LocalCoreStartupParameter.iHeight);
ini.Set("Interface", "ShowWiimoteLeds", m_LocalCoreStartupParameter.bWiiLeds);
ini.Set("Interface", "ShowWiimoteSpeakers", m_LocalCoreStartupParameter.bWiiSpeakers);
ini.Set("Interface", "Language", m_InterfaceLanguage);
ini.Set("Interface", "ShowToolbar", m_InterfaceToolbar);
ini.Set("Interface", "ShowStatusbar", m_InterfaceStatusbar);
@@ -197,8 +195,6 @@ void SConfig::LoadSettings()
ini.Get("Interface", "MainWindowPosY", &m_LocalCoreStartupParameter.iPosY, 100);
ini.Get("Interface", "MainWindowWidth", &m_LocalCoreStartupParameter.iWidth, 800);
ini.Get("Interface", "MainWindowHeight", &m_LocalCoreStartupParameter.iHeight, 600);
ini.Get("Interface", "ShowWiimoteLeds", &m_LocalCoreStartupParameter.bWiiLeds, false);
ini.Get("Interface", "ShowWiimoteSpeakers", &m_LocalCoreStartupParameter.bWiiSpeakers, false);
ini.Get("Interface", "Language", (int*)&m_InterfaceLanguage, 0);
ini.Get("Interface", "ShowToolbar", &m_InterfaceToolbar, true);
ini.Get("Interface", "ShowStatusbar", &m_InterfaceStatusbar, true);
+14 -55
View File
@@ -29,11 +29,6 @@
#include "MathUtil.h"
#include "MemoryUtil.h"
#if defined(HAVE_X11) && HAVE_X11
#include <X11/Xlib.h>
#include <X11/keysym.h>
#endif
#include "Console.h"
#include "Core.h"
#include "CPUDetect.h"
@@ -252,45 +247,6 @@ void Stop() // - Hammertime!
g_EmuThread = 0;
}
#if defined(HAVE_X11) && HAVE_X11
void ProcessXEvents(void)
{
if (GetState() == CORE_PAUSE)
{
Display *dpy = (Display *)g_pWindowHandle;
XEvent event;
KeySym key;
int num_events;
for (num_events = XPending(dpy);num_events > 0;num_events--)
{
XNextEvent(dpy, &event);
switch(event.type) {
case KeyPress:
key = XLookupKeysym((XKeyEvent*)&event, 0);
if (key == XK_Escape)
Host_Message(WM_USER_PAUSE);
case ClientMessage:
if ((ulong) event.xclient.data.l[0] == XInternAtom(dpy, "WM_DELETE_WINDOW", False))
Host_Message(WM_USER_STOP);
break;
default:
break;
}
}
}
}
THREAD_RETURN XEventThread(void *pArg)
{
while (PowerPC::GetState() != PowerPC::CPU_POWERDOWN)
{
ProcessXEvents();
Common::SleepCurrentThread(200);
}
return 0;
}
#endif
// Create the CPU thread. which would be a CPU + Video thread in Single Core mode.
THREAD_RETURN CpuThread(void *pArg)
@@ -366,6 +322,9 @@ THREAD_RETURN EmuThread(void *pArg)
VideoInitialize.pScheduleEvent_Threadsafe = CoreTiming::ScheduleEvent_Threadsafe;
// This is first the m_Panel handle, then it is updated to have the new window handle
VideoInitialize.pWindowHandle = _CoreParameter.hMainWindow;
#if defined(HAVE_X11) && HAVE_X11 && defined(HAVE_GTK2) && HAVE_GTK2
VideoInitialize.pPanel = _CoreParameter.hMainWindow;
#endif
VideoInitialize.pLog = Callback_VideoLog;
VideoInitialize.pSysMessage = Host_SysMessage;
VideoInitialize.pRequestWindowSize = NULL; //Callback_VideoRequestWindowSize;
@@ -386,7 +345,7 @@ THREAD_RETURN EmuThread(void *pArg)
// Under linux, this is an X11 Display, not a HWND!
g_pWindowHandle = (HWND)VideoInitialize.pWindowHandle;
#if defined(HAVE_X11) && HAVE_X11
g_pXWindow = (Window *)VideoInitialize.pXWindow;
g_pXWindow = (void *)VideoInitialize.pXWindow;
#endif
Callback_PeekMessages = VideoInitialize.pPeekMessages;
g_pUpdateFPSDisplay = VideoInitialize.pUpdateFPSDisplay;
@@ -415,6 +374,9 @@ THREAD_RETURN EmuThread(void *pArg)
PADInitialize.hWnd = g_pWindowHandle;
#if defined(HAVE_X11) && HAVE_X11
PADInitialize.pXWindow = g_pXWindow;
#if defined(HAVE_GTK2) && HAVE_GTK2
PADInitialize.pPanel = VideoInitialize.pPanel;
#endif
#endif
PADInitialize.pLog = Callback_PADLog;
// This is may be needed to avoid a SDL problem
@@ -427,6 +389,9 @@ THREAD_RETURN EmuThread(void *pArg)
SWiimoteInitialize WiimoteInitialize;
WiimoteInitialize.hWnd = g_pWindowHandle;
#if defined(HAVE_X11) && HAVE_X11
#if defined(HAVE_GTK2) && HAVE_GTK2
WiimoteInitialize.pPanel = VideoInitialize.pPanel;
#endif
WiimoteInitialize.pXWindow = g_pXWindow;
#endif
WiimoteInitialize.ISOId = Ascii2Hex(_CoreParameter.m_strUniqueID);
@@ -457,10 +422,6 @@ THREAD_RETURN EmuThread(void *pArg)
// Spawn the CPU thread
Common::Thread *cpuThread = NULL;
#if defined(HAVE_X11) && HAVE_X11
Common::Thread *xEventThread = NULL;
#endif
// ENTER THE VIDEO THREAD LOOP
if (_CoreParameter.bCPUThread)
{
@@ -469,9 +430,6 @@ THREAD_RETURN EmuThread(void *pArg)
Plugins.GetVideo()->Video_Prepare(); // wglMakeCurrent
cpuThread = new Common::Thread(CpuThread, pArg);
#if defined(HAVE_X11) && HAVE_X11
xEventThread = new Common::Thread(XEventThread, pArg);
#endif
Common::SetCurrentThreadName("Video thread");
if (g_pUpdateFPSDisplay != NULL)
@@ -506,9 +464,6 @@ THREAD_RETURN EmuThread(void *pArg)
{
if (Callback_PeekMessages)
Callback_PeekMessages();
#if defined(HAVE_X11) && HAVE_X11
ProcessXEvents();
#endif
Common::SleepCurrentThread(20);
}
@@ -815,11 +770,15 @@ void Callback_KeyPress(int key, bool shift, bool control)
State_UndoLoadState();
}
#if defined(HAVE_X11) && HAVE_X11
if (key == 0)
Host_Message(WM_USER_CREATE);
// 0x1b == VK_ESCAPE
if (key == 0x1b)
Host_Message(WM_USER_STOP);
if (key == 0x1c)
Host_Message(WM_USER_PAUSE);
if (key == 0x1d)
Host_Message(TOGGLE_FULLSCREEN);
#endif
}
+1 -2
View File
@@ -47,7 +47,7 @@ SCoreStartupParameter::SCoreStartupParameter()
bEnableCheats(false), bEnableIsoCache(false),
bRunCompareServer(false), bRunCompareClient(false),
iTLBHack(0), SelectedLanguage(0),
bWii(false), bWiiLeds(false), bWiiSpeakers(false),
bWii(false),
bConfirmStop(false), bHideCursor(false),
bAutoHideCursor(false), bUsePanicHandlers(true),
iTheme(0),
@@ -91,7 +91,6 @@ void SCoreStartupParameter::LoadDefaults()
// These work fine in 32bit OSX
// Since the reason why 64bit OSX fails out is due to casting (u32)(u64)
// Since all 64bit applications are above the 32bit memory boundary
bJITLoadStoreOff = true;
bJITLoadStorePairedOff = true;
#endif
//#elif defined(__linux__)
+1 -2
View File
@@ -73,8 +73,7 @@ struct SCoreStartupParameter
int SelectedLanguage;
// Wii settings
bool bWii, bWiiLeds, bWiiSpeakers;
bool bWii;
// Interface settings
bool bConfirmStop, bHideCursor, bAutoHideCursor, bUsePanicHandlers;
+2 -2
View File
@@ -27,8 +27,8 @@
bool MicButton = false;
bool IsOpen;
//#define HAVE_PORTAUDIO
#if !defined(HAVE_PORTAUDIO) || !HAVE_PORTAUDIO
// Unfortunately this must be enabled in Common.h for windows users. Scons should enable it otherwise7
#if !HAVE_PORTAUDIO
void SetMic(bool Value){}
-4
View File
@@ -53,8 +53,4 @@ void Host_UpdateStatusBar(const char* _pText, int Filed = 0);
void Host_SysMessage(const char *fmt, ...);
void Host_SetWiiMoteConnectionState(int _State);
void Host_UpdateLeds(int bits);
void Host_UpdateSpeakerStatus(int index, int bits);
void Host_UpdateStatus();
#endif
@@ -146,75 +146,10 @@ bool CWII_IPC_HLE_WiiMote::LinkChannel()
}
m_Connected = 3;
UpdateStatus();
return false;
}
// ===================================================
/* Send a status report to the status bar. */
// ----------------
void CWII_IPC_HLE_WiiMote::ShowStatus(const void* _pData)
{
// Check if it's enabled
SCoreStartupParameter& StartUp = SConfig::GetInstance().m_LocalCoreStartupParameter;
bool LedsOn = StartUp.bWiiLeds;
bool SpeakersOn = StartUp.bWiiSpeakers;
const u8* data = (const u8*)_pData;
// Get the last four bits with LED info
if (LedsOn)
{
if (data[1] == 0x11)
{
int led_bits = (data[2] >> 4);
Host_UpdateLeds(led_bits);
}
}
int speaker_bits = 0;
if (SpeakersOn)
{
u8 Bits = 0;
switch (data[1])
{
case 0x14: // Enable and disable speakers
if (data[2] == 0x02) // Off
Bits = 0;
else if (data[2] == 0x06) // On
Bits = 1;
Host_UpdateSpeakerStatus(0, Bits);
break;
case 0x19: // Mute and unmute
// Get the value
if (data[2] == 0x02) // Unmute
Bits = 1;
else if (data[2] == 0x06) // Mute
Bits = 0;
Host_UpdateSpeakerStatus(1, Bits);
break;
// Write to speaker registry, or write sound
case 0x16:
case 0x18:
// Turn on the activity light
Host_UpdateSpeakerStatus(2, 1);
break;
}
}
}
// Turn off the activity icon again
void CWII_IPC_HLE_WiiMote::UpdateStatus()
{
// Check if it's enabled
if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bWiiSpeakers)
return;
Host_UpdateStatus();
}
//
//
//
@@ -335,13 +270,10 @@ void CWII_IPC_HLE_WiiMote::ExecuteL2capCmd(u8* _pData, u32 _Size)
case HID_CONTROL_CHANNEL:
mote->Wiimote_ControlChannel(m_ConnectionHandle & 0xFF, pHeader->CID, pData, DataSize);
// Call Wiimote Plugin
break;
case HID_INTERRUPT_CHANNEL:
ShowStatus(pData);
mote->Wiimote_InterruptChannel(m_ConnectionHandle & 0xFF, pHeader->CID, pData, DataSize);
// Call Wiimote Plugin
break;
default:
@@ -130,66 +130,33 @@ struct SL2CAP_CommandDisconnectionResponse // 0x07
#pragma pack(pop)
class CBigEndianBuffer
{
public:
CBigEndianBuffer(u8* pBuffer)
: m_pBuffer(pBuffer)
{
}
CBigEndianBuffer(u8* pBuffer) : m_pBuffer(pBuffer) {}
u8 Read8(u32 offset)
{
return m_pBuffer[offset];
}
u8 Read8(u32 offset) { return m_pBuffer[offset]; }
u16 Read16(u32 offset) { return Common::swap16(*(u16*)&m_pBuffer[offset]); }
u32 Read32(u32 offset) { return Common::swap32(*(u32*)&m_pBuffer[offset]); }
u16 Read16(u32 offset)
{
return Common::swap16(*(u16*)&m_pBuffer[offset]);
}
void Write8(u32 offset, u8 data) { m_pBuffer[offset] = data; }
void Write16(u32 offset, u16 data) { *(u16*)&m_pBuffer[offset] = Common::swap16(data); }
void Write32(u32 offset, u32 data) { *(u32*)&m_pBuffer[offset] = Common::swap32(data); }
u32 Read32(u32 offset)
{
return Common::swap32(*(u32*)&m_pBuffer[offset]);
}
void Write8(u32 offset, u8 data)
{
m_pBuffer[offset] = data;
}
void Write16(u32 offset, u16 data)
{
*(u16*)&m_pBuffer[offset] = Common::swap16(data);
}
void Write32(u32 offset, u32 data)
{
*(u32*)&m_pBuffer[offset] = Common::swap32(data);
}
u8* GetPointer(u32 offset)
{
return &m_pBuffer[offset];
}
u8* GetPointer(u32 offset) { return &m_pBuffer[offset]; }
private:
u8* m_pBuffer;
};
class CWII_IPC_HLE_WiiMote
{
public:
CWII_IPC_HLE_WiiMote(CWII_IPC_HLE_Device_usb_oh1_57e_305* _pHost, int _Number, bool ready = false);
virtual ~CWII_IPC_HLE_WiiMote()
{}
virtual ~CWII_IPC_HLE_WiiMote() {}
void DoState(PointerWrap &p);
@@ -200,8 +167,6 @@ public:
bool LinkChannel();
void ResetChannels();
void Activate(bool ready);
void ShowStatus(const void* _pData); // Show status
void UpdateStatus(); // Update status
void ExecuteL2capCmd(u8* _pData, u32 _Size); // From CPU
void ReceiveL2capData(u16 scid, const void* _pData, u32 _Size); // From wiimote
@@ -220,7 +185,6 @@ public:
const u8* GetLinkKey() const { return m_LinkKey; }
private:
// -1: inactive, 0: ready, 1: connecting 2: linking 3: connected & linked
int m_Connected;
@@ -277,9 +241,7 @@ private:
void ReceiveConfigurationResponse(u8 _Ident, u8* _pData, u32 _Size);
// some new ugly stuff
//
// should be inside the plugin
//
void HandleSDP(u16 _SCID, u8* _pData, u32 _Size);
void SDPSendServiceSearchResponse(u16 _SCID, u16 _TransactionID, u8* _pServiceSearchPattern, u16 _MaximumServiceRecordCount);
@@ -477,9 +477,13 @@ void divwx(UGeckoInstruction _inst)
s32 b = m_GPR[_inst.RB];
if (b == 0 || ((u32)a == 0x80000000 && b == -1))
{
if (_inst.OE)
if (_inst.OE)
// should set OV
PanicAlert("OE: divwx");
//else PanicAlert("Div by zero", "divwux");
if (((u32)a & 0x80000000) && b == 0)
m_GPR[_inst.RD] = -1;
else
m_GPR[_inst.RD] = 0;
}
else
m_GPR[_inst.RD] = (u32)(a / b);
@@ -493,17 +497,17 @@ void divwux(UGeckoInstruction _inst)
u32 a = m_GPR[_inst.RA];
u32 b = m_GPR[_inst.RB];
if (b == 0) // || (a == 0x80000000 && b == 0xFFFFFFFF))
if (b == 0)
{
if (_inst.OE)
if (_inst.OE)
// should set OV
PanicAlert("OE: divwux");
//else PanicAlert("Div by zero", "divwux");
m_GPR[_inst.RD] = 0;
}
else
{
m_GPR[_inst.RD] = a / b;
if (_inst.Rc) Helper_UpdateCR0(m_GPR[_inst.RD]);
}
if (_inst.Rc) Helper_UpdateCR0(m_GPR[_inst.RD]);
}
void mulhwx(UGeckoInstruction _inst)
@@ -572,7 +576,7 @@ void subfex(UGeckoInstruction _inst)
m_GPR[_inst.RD] = (~a) + b + carry;
SetCarry(Helper_Carry(~a, b) || Helper_Carry((~a) + b, carry));
if (_inst.OE) PanicAlert("OE: subfcx");
if (_inst.OE) PanicAlert("OE: subfex");
if (_inst.Rc) Helper_UpdateCR0(m_GPR[_inst.RD]);
}
@@ -388,34 +388,77 @@ void Jit64::subfic(UGeckoInstruction inst)
void Jit64::subfcx(UGeckoInstruction inst)
{
INSTRUCTION_START;
Default(inst);
return;
/*
u32 a = m_GPR[_inst.RA];
u32 b = m_GPR[_inst.RB];
m_GPR[_inst.RD] = b - a;
SetCarry(a == 0 || Helper_Carry(b, 0-a));
JITDISABLE(Integer)
int a = inst.RA, b = inst.RB, d = inst.RD;
gpr.Lock(a, b, d);
if(d != a && d != b)
gpr.LoadToX64(d, false, true);
else
gpr.LoadToX64(d, true, true);
if (_inst.OE) PanicAlert("OE: subfcx");
if (_inst.Rc) Helper_UpdateCR0(m_GPR[_inst.RD]);
*/
// For some reason, I could not get the jit versions of sub*
// working with x86 sub...so we use the ~a + b + 1 method
JitClearCA();
MOV(32, R(EAX), gpr.R(a));
NOT(32, R(EAX));
ADD(32, R(EAX), gpr.R(b));
FixupBranch carry1 = J_CC(CC_NC);
JitSetCA();
SetJumpTarget(carry1);
ADD(32, R(EAX), Imm32(1));
FixupBranch carry2 = J_CC(CC_NC);
JitSetCA();
SetJumpTarget(carry2);
MOV(32, gpr.R(d), R(EAX));
gpr.UnlockAll();
if (inst.OE) PanicAlert("OE: subfcx");
if (inst.Rc) {
CALL((u8*)asm_routines.computeRc);
}
}
void Jit64::subfex(UGeckoInstruction inst)
{
INSTRUCTION_START;
Default(inst);
return;
/*
u32 a = m_GPR[_inst.RA];
u32 b = m_GPR[_inst.RB];
int carry = GetCarry();
m_GPR[_inst.RD] = (~a) + b + carry;
SetCarry(Helper_Carry(~a, b) || Helper_Carry((~a) + b, carry));
JITDISABLE(Integer)
int a = inst.RA, b = inst.RB, d = inst.RD;
gpr.FlushLockX(ECX);
gpr.Lock(a, b, d);
if(d != a && d != b)
gpr.LoadToX64(d, false, true);
else
gpr.LoadToX64(d, true, true);
if (_inst.OE) PanicAlert("OE: subfcx");
if (_inst.Rc) Helper_UpdateCR0(m_GPR[_inst.RD]);
*/
// Get CA
MOV(32, R(ECX), M(&PowerPC::ppcState.spr[SPR_XER]));
SHR(32, R(ECX), Imm8(29));
AND(32, R(ECX), Imm32(1));
// Don't need it anymore
JitClearCA();
// ~a + b
MOV(32, R(EAX), gpr.R(a));
NOT(32, R(EAX));
ADD(32, R(EAX), gpr.R(b));
FixupBranch carry1 = J_CC(CC_NC);
JitSetCA();
SetJumpTarget(carry1);
// + CA
ADD(32, R(EAX), R(ECX));
FixupBranch carry2 = J_CC(CC_NC);
JitSetCA();
SetJumpTarget(carry2);
MOV(32, gpr.R(d), R(EAX));
gpr.UnlockAll();
gpr.UnlockAllX();
if (inst.OE) PanicAlert("OE: subfex");
if (inst.Rc) {
CALL((u8*)asm_routines.computeRc);
}
}
void Jit64::subfx(UGeckoInstruction inst)
@@ -503,10 +546,10 @@ void Jit64::mulhwux(UGeckoInstruction inst)
}
}
// skipped some of the special handling in here - if we get crashes, let the interpreter handle this op
void Jit64::divwux(UGeckoInstruction inst) {
Default(inst); return;
void Jit64::divwux(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)
int a = inst.RA, b = inst.RB, d = inst.RD;
gpr.FlushLockX(EDX);
gpr.Lock(a, b, d);
@@ -518,8 +561,16 @@ void Jit64::divwux(UGeckoInstruction inst) {
MOV(32, R(EAX), gpr.R(a));
XOR(32, R(EDX), R(EDX));
gpr.KillImmediate(b);
CMP(32, gpr.R(b), Imm32(0));
// doesn't handle if OE is set, but int doesn't either...
FixupBranch not_div_by_zero = J_CC(CC_NZ);
MOV(32, gpr.R(d), R(EDX));
MOV(32, R(EAX), gpr.R(d));
FixupBranch end = J();
SetJumpTarget(not_div_by_zero);
DIV(32, gpr.R(b));
MOV(32, gpr.R(d), R(EAX));
SetJumpTarget(end);
gpr.UnlockAll();
gpr.UnlockAllX();
if (inst.Rc) {
@@ -575,6 +626,31 @@ void Jit64::addx(UGeckoInstruction inst)
}
gpr.UnlockAll();
}
else if( a == b && b == d && a == d)
{
gpr.Lock(d);
gpr.LoadToX64(d, true);
ADD(32, gpr.R(d), gpr.R(d));
if (inst.Rc)
{
MOV(32, R(EAX), gpr.R(d));
CALL((u8*)asm_routines.computeRc);
}
gpr.UnlockAll();
}
else if( a == b && b != d)
{
gpr.Lock(a, d);
gpr.LoadToX64(d, false);
MOV(32, gpr.R(d), gpr.R(a));
ADD(32, gpr.R(d), gpr.R(d));
if (inst.Rc)
{
MOV(32, R(EAX), gpr.R(d));
CALL((u8*)asm_routines.computeRc);
}
gpr.UnlockAll();
}
else
{
Default(inst); return;
@@ -317,7 +317,9 @@ void Jit64::stX(UGeckoInstruction inst)
case 38: accessSize = 8; break; //stb
default: _assert_msg_(DYNA_REC, 0, "AWETKLJASDLKF"); return;
}
#ifndef __APPLE__ && _M_X64
//(Sonicadvance1) This code path fails in OSX, not 100% sure why
if (gpr.R(a).IsImm())
{
// If we already know the address through constant folding, we can do some
@@ -353,6 +355,7 @@ void Jit64::stX(UGeckoInstruction inst)
}
// Other IO not worth the trouble.
}
#endif
// Optimized stack access?
if (accessSize == 32 && !gpr.R(a).IsImm() && a == 1 && js.st.isFirstBlockOfFunction && jo.optimizeStack)
@@ -37,6 +37,60 @@ using namespace Gen;
static int temp32;
#ifdef __APPLE__ && _M_X64
void CommonAsmRoutines::GenFifoWrite(int size)
{
// Assume value in ABI_PARAM1
PUSH(RSI);
if (size != 32)
PUSH(EDX);
BSWAP(size, ABI_PARAM1);
MOV(32, R(EAX), Imm32((u64)GPFifo::m_gatherPipe));
MOV(64, R(RSI), M(&GPFifo::m_gatherPipeCount));
if (size != 32) {
MOV(32, R(EDX), R(ABI_PARAM1));
MOV(size, MComplex(RAX, RSI, 1, 0), R(EDX));
} else {
MOV(size, MComplex(RAX, RSI, 1, 0), R(ABI_PARAM1));
}
ADD(64, R(RSI), Imm8(size >> 3));
MOV(64, M(&GPFifo::m_gatherPipeCount), R(RSI));
if (size != 32)
POP(EDX);
POP(RSI);
RET();
}
void CommonAsmRoutines::GenFifoFloatWrite()
{
// Assume value in XMM0
PUSH(RSI);
PUSH(EDX);
MOVSS(M(&temp32), XMM0);
MOV(32, R(EDX), M(&temp32));
BSWAP(32, EDX);
MOV(64, R(RAX), Imm64((u64)GPFifo::m_gatherPipe));
MOV(64, R(RSI), M(&GPFifo::m_gatherPipeCount));
MOV(32, MComplex(RAX, RSI, 1, 0), R(EDX));
ADD(64, R(RSI), Imm8(4));
MOV(64, M(&GPFifo::m_gatherPipeCount), R(RSI));
POP(EDX);
POP(RSI);
RET();
}
void CommonAsmRoutines::GenFifoXmm64Write()
{
// Assume value in XMM0. Assume pre-byteswapped (unlike the others here!)
PUSH(RSI);
MOV(64, R(RAX), Imm32((u64)GPFifo::m_gatherPipe));
MOV(64, R(RSI), M(&GPFifo::m_gatherPipeCount));
MOVQ_xmm(MComplex(RAX, RSI, 1, 0), XMM0);
ADD(64, R(RSI), Imm8(8));
MOV(64, M(&GPFifo::m_gatherPipeCount), R(RSI));
POP(RSI);
RET();
}
#else
void CommonAsmRoutines::GenFifoWrite(int size)
{
// Assume value in ABI_PARAM1
@@ -59,7 +113,6 @@ void CommonAsmRoutines::GenFifoWrite(int size)
POP(ESI);
RET();
}
void CommonAsmRoutines::GenFifoFloatWrite()
{
// Assume value in XMM0
@@ -77,7 +130,6 @@ void CommonAsmRoutines::GenFifoFloatWrite()
POP(ESI);
RET();
}
void CommonAsmRoutines::GenFifoXmm64Write()
{
// Assume value in XMM0. Assume pre-byteswapped (unlike the others here!)
@@ -86,10 +138,11 @@ void CommonAsmRoutines::GenFifoXmm64Write()
MOV(32, R(ESI), M(&GPFifo::m_gatherPipeCount));
MOVQ_xmm(MComplex(RAX, RSI, 1, 0), XMM0);
ADD(32, R(ESI), Imm8(8));
MOV(32, M(&GPFifo::m_gatherPipeCount), R(ESI));
POP(ESI);
RET();
MOV(32, M(&GPFifo::m_gatherPipeCount), R(ESI));
POP(ESI);
RET();
}
#endif
// Safe + Fast Quantizers, originally from JITIL by magumagu
+1 -1
View File
@@ -138,7 +138,7 @@ libs = [
'bdisasm',
'inputcommon',
'lua',
'sfml'
'sfml-network'
]
env_core = env.Clone();
+4
View File
@@ -31,7 +31,11 @@
#include <string>
#if defined(SHARED_LZO) && SHARED_LZO
#include <lzo/lzo1x.h>
#else
#include "minilzo.h"
#endif
// TODO: Move to namespace
+3 -1
View File
@@ -56,6 +56,7 @@ DriveReader::DriveReader(const char *drive)
0, &dwNotUsed, NULL);
#endif
#else
SectorReader::SetSectorSize(2048);
file_ = fopen(drive, "rb");
if (file_)
{
@@ -83,7 +84,8 @@ DriveReader::~DriveReader()
hDisc = INVALID_HANDLE_VALUE;
}
#else
fclose(file_);
if (file_)
fclose(file_);
file_ = 0;
#endif
}
+7 -11
View File
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9,00"
Version="9.00"
Name="Dolphin"
ProjectGUID="{A72606EF-C5C1-4954-90AD-F0F93A8D97D9}"
RootNamespace="DolphinWX"
@@ -31,7 +31,7 @@
<Tool
Name="VCPreBuildEventTool"
CommandLine="&quot;$(ProjectDir)..\Common\SubWCRev.exe&quot; &quot;$(SolutionDir)\.&quot; &quot;$(ProjectDir)..\Common\src\svnrev_template.h&quot; &quot;$(ProjectDir)..\Common\src\svnrev.h&quot;"
ExcludedFromBuild="false"
ExcludedFromBuild="true"
/>
<Tool
Name="VCCustomBuildTool"
@@ -147,7 +147,7 @@
<Tool
Name="VCPreBuildEventTool"
CommandLine="&quot;$(ProjectDir)..\Common\SubWCRev.exe&quot; &quot;$(SolutionDir)\.&quot; &quot;$(ProjectDir)..\Common\src\svnrev_template.h&quot; &quot;$(ProjectDir)..\Common\src\svnrev.h&quot;"
ExcludedFromBuild="false"
ExcludedFromBuild="true"
/>
<Tool
Name="VCCustomBuildTool"
@@ -263,7 +263,7 @@
<Tool
Name="VCPreBuildEventTool"
CommandLine="&quot;$(ProjectDir)..\Common\SubWCRev.exe&quot; &quot;$(SolutionDir)\.&quot; &quot;$(ProjectDir)..\Common\src\svnrev_template.h&quot; &quot;$(ProjectDir)..\Common\src\svnrev.h&quot;"
ExcludedFromBuild="false"
ExcludedFromBuild="true"
/>
<Tool
Name="VCCustomBuildTool"
@@ -374,7 +374,7 @@
<Tool
Name="VCPreBuildEventTool"
CommandLine="&quot;$(ProjectDir)..\Common\SubWCRev.exe&quot; &quot;$(SolutionDir)\.&quot; &quot;$(ProjectDir)..\Common\src\svnrev_template.h&quot; &quot;$(ProjectDir)..\Common\src\svnrev.h&quot;"
ExcludedFromBuild="false"
ExcludedFromBuild="true"
/>
<Tool
Name="VCCustomBuildTool"
@@ -485,7 +485,7 @@
<Tool
Name="VCPreBuildEventTool"
CommandLine="&quot;$(ProjectDir)..\Common\SubWCRev.exe&quot; &quot;$(SolutionDir)\.&quot; &quot;$(ProjectDir)..\Common\src\svnrev_template.h&quot; &quot;$(ProjectDir)..\Common\src\svnrev.h&quot;"
ExcludedFromBuild="false"
ExcludedFromBuild="true"
/>
<Tool
Name="VCCustomBuildTool"
@@ -600,7 +600,7 @@
<Tool
Name="VCPreBuildEventTool"
CommandLine="&quot;$(ProjectDir)..\Common\SubWCRev.exe&quot; &quot;$(SolutionDir)\.&quot; &quot;$(ProjectDir)..\Common\src\svnrev_template.h&quot; &quot;$(ProjectDir)..\Common\src\svnrev.h&quot;"
ExcludedFromBuild="false"
ExcludedFromBuild="true"
/>
<Tool
Name="VCCustomBuildTool"
@@ -855,10 +855,6 @@
RelativePath=".\Src\FrameTools.cpp"
>
</File>
<File
RelativePath=".\Src\FrameWiimote.cpp"
>
</File>
<File
RelativePath=".\src\GameListCtrl.cpp"
>
+1 -1
View File
@@ -46,7 +46,7 @@ void AboutDolphin::CreateGUIControls()
DolphinLogo = new wxBitmap(iDolphinLogo);
sbDolphinLogo = new wxStaticBitmap(this, ID_LOGO, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0);
sbDolphinLogo->SetBitmap(*DolphinLogo);
std::string Text = std::string("Dolphin SVN revision ") + SVN_REV_STR +"\n" "Copyright (c) 2003-2010+ Dolphin Team\n"
std::string Text = std::string("Dolphin ") + SVN_REV_STR +"\n" "Copyright (c) 2003-2010+ Dolphin Team\n"
"Dolphin is a Gamecube/Wii emulator, which was originally written by F|RES and ector.\n"
"Today Dolphin is an open source project with many contributors, too many to list.\n"
"If interested, just go check out the project page at http://code.google.com/p/dolphin-emu.\n\n"
+1 -4
View File
@@ -120,7 +120,7 @@ bool BootCore(const std::string& _rFilename)
if (unique_id.size() == 6 && game_ini.Load(StartUp.m_strGameIni.c_str()))
{
// General settings
game_ini.Get("Core", "CPUOnThread", &StartUp.bCPUThread, StartUp.bCPUThread);
game_ini.Get("Core", "CPUThread", &StartUp.bCPUThread, StartUp.bCPUThread);
game_ini.Get("Core", "SkipIdle", &StartUp.bSkipIdle, StartUp.bSkipIdle);
game_ini.Get("Core", "EnableFPRF", &StartUp.bEnableFPRF, StartUp.bEnableFPRF);
game_ini.Get("Core", "TLBHack", &StartUp.iTLBHack, StartUp.iTLBHack);
@@ -139,9 +139,6 @@ bool BootCore(const std::string& _rFilename)
{
// Save the window handle of the eventual parent to the rendering window
StartUp.hMainWindow = main_frame->GetRenderHandle();
// Now that we know if we have a Wii game we can run this
main_frame->ModifyStatusBar();
}
#endif
// Init the core
+9 -25
View File
@@ -56,8 +56,6 @@ EVT_CHECKBOX(ID_INTERFACE_HIDECURSOR, CConfigMain::CoreSettingsChanged)
EVT_CHECKBOX(ID_INTERFACE_AUTOHIDECURSOR, CConfigMain::CoreSettingsChanged)
#endif
EVT_RADIOBOX(ID_INTERFACE_THEME, CConfigMain::CoreSettingsChanged)
EVT_CHECKBOX(ID_INTERFACE_WIIMOTE_LEDS, CConfigMain::CoreSettingsChanged)
EVT_CHECKBOX(ID_INTERFACE_WIIMOTE_SPEAKERS, CConfigMain::CoreSettingsChanged)
EVT_CHOICE(ID_INTERFACE_LANG, CConfigMain::CoreSettingsChanged)
EVT_CHECKBOX(ID_ALWAYS_HLE_BS2, CConfigMain::CoreSettingsChanged)
@@ -229,8 +227,6 @@ void CConfigMain::InitializeGUIValues()
AutoHideCursor->SetValue(SConfig::GetInstance().m_LocalCoreStartupParameter.bAutoHideCursor);
HideCursor->SetValue(SConfig::GetInstance().m_LocalCoreStartupParameter.bHideCursor);
#endif
WiimoteStatusLEDs->SetValue(SConfig::GetInstance().m_LocalCoreStartupParameter.bWiiLeds);
WiimoteStatusSpeakers->SetValue(SConfig::GetInstance().m_LocalCoreStartupParameter.bWiiSpeakers);
Theme->SetSelection(SConfig::GetInstance().m_LocalCoreStartupParameter.iTheme);
// need redesign
InterfaceLang->SetSelection(SConfig::GetInstance().m_InterfaceLanguage);
@@ -289,8 +285,6 @@ void CConfigMain::InitializeGUITooltips()
HideCursor->SetToolTip(wxT("This will always hide the cursor when it's over the rendering window.")
wxT("\nIt can be convenient in a Wii game that already has a cursor."));
#endif
WiimoteStatusLEDs->SetToolTip(wxT("Show which wiimotes are connected in the statusbar."));
WiimoteStatusSpeakers->SetToolTip(wxT("Show wiimote speaker status in the statusbar."));
InterfaceLang->SetToolTip(wxT("For the time being this will only change the text shown in")
wxT("\nthe game list of PAL GC games."));
// Themes: Copyright notice
@@ -352,11 +346,6 @@ void CConfigMain::CreateGUIControls()
AutoHideCursor = new wxCheckBox(GeneralPage, ID_INTERFACE_AUTOHIDECURSOR, wxT("Auto"));
HideCursor = new wxCheckBox(GeneralPage, ID_INTERFACE_HIDECURSOR, wxT("Always"));
#endif
// Wiimote status in statusbar
wxStaticText *WiimoteStatusText = new wxStaticText(GeneralPage, ID_INTERFACE_WIIMOTE_TEXT, wxT("Show wiimote status:"), wxDefaultPosition, wxDefaultSize);
WiimoteStatusLEDs = new wxCheckBox(GeneralPage, ID_INTERFACE_WIIMOTE_LEDS, wxT("LEDs"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator);
WiimoteStatusSpeakers = new wxCheckBox(GeneralPage, ID_INTERFACE_WIIMOTE_SPEAKERS, wxT("Speakers"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator);
// Interface Language
// At the moment this only changes the language displayed in m_gamelistctrl
// If someone wants to control the whole GUI's language, it should be set here too
@@ -396,11 +385,6 @@ void CConfigMain::CreateGUIControls()
sHideCursor->Add(HideCursor, 0, wxLEFT, 5);
sbInterface->Add(sHideCursor, 0, wxALL, 5);
#endif
wxBoxSizer *sWiimoteStatus = new wxBoxSizer(wxHORIZONTAL);
sWiimoteStatus->Add(WiimoteStatusText);
sWiimoteStatus->Add(WiimoteStatusLEDs, 0, wxLEFT, 5);
sWiimoteStatus->Add(WiimoteStatusSpeakers, 0, wxLEFT, 5);
sbInterface->Add(sWiimoteStatus, 0, wxALL, 5);
sbInterface->Add(Theme, 0, wxEXPAND | wxALL, 5);
wxBoxSizer *sInterfaceLanguage = new wxBoxSizer(wxHORIZONTAL);
sInterfaceLanguage->Add(InterfaceLangText, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
@@ -430,7 +414,11 @@ void CConfigMain::CreateGUIControls()
GCEXIDeviceText[1] = new wxStaticText(GamecubePage, ID_GC_EXIDEVICE_SLOTB_TEXT, wxT("Slot B"), wxDefaultPosition, wxDefaultSize);
GCEXIDeviceText[2] = new wxStaticText(GamecubePage, ID_GC_EXIDEVICE_SP1_TEXT, wxT("SP1 "), wxDefaultPosition, wxDefaultSize);
GCEXIDeviceText[2]->SetToolTip(wxT("Serial Port 1 - This is the port which devices such as the net adapter use"));
const wxString SlotDevices[] = {wxT(DEV_NONE_STR),wxT(DEV_DUMMY_STR),wxT(EXIDEV_MEMCARD_STR), wxT(EXIDEV_MIC_STR)};
const wxString SlotDevices[] = {wxT(DEV_NONE_STR),wxT(DEV_DUMMY_STR),wxT(EXIDEV_MEMCARD_STR)
#if HAVE_PORTAUDIO
, wxT(EXIDEV_MIC_STR)
#endif
};
static const int numSlotDevices = sizeof(SlotDevices)/sizeof(wxString);
const wxString SP1Devices[] = {wxT(DEV_NONE_STR),wxT(DEV_DUMMY_STR),wxT(EXIDEV_BBA_STR),wxT(EXIDEV_AM_BB_STR)};
static const int numSP1Devices = sizeof(SP1Devices)/sizeof(wxString);
@@ -475,9 +463,11 @@ void CConfigMain::CreateGUIControls()
GCSIDeviceText[1] = new wxStaticText(GamecubePage, ID_GC_SIDEVICE_TEXT, wxT("Port 2"), wxDefaultPosition, wxDefaultSize);
GCSIDeviceText[2] = new wxStaticText(GamecubePage, ID_GC_SIDEVICE_TEXT, wxT("Port 3"), wxDefaultPosition, wxDefaultSize);
GCSIDeviceText[3] = new wxStaticText(GamecubePage, ID_GC_SIDEVICE_TEXT, wxT("Port 4"), wxDefaultPosition, wxDefaultSize);
const wxString SIDevices[] = {wxT(DEV_NONE_STR),wxT(SIDEV_STDCONT_STR),wxT(SIDEV_GBA_STR),wxT(SIDEV_AM_BB_STR)};
const wxString SIPort1Devices[] = {wxT(DEV_NONE_STR),wxT(SIDEV_STDCONT_STR),wxT(SIDEV_GBA_STR),wxT(SIDEV_AM_BB_STR)};
static const int numSIPort1Devices = sizeof(SIPort1Devices)/sizeof(wxString);
const wxString SIDevices[] = {wxT(DEV_NONE_STR),wxT(SIDEV_STDCONT_STR),wxT(SIDEV_GBA_STR)};
static const int numSIDevices = sizeof(SIDevices)/sizeof(wxString);
GCSIDevice[0] = new wxChoice(GamecubePage, ID_GC_SIDEVICE0, wxDefaultPosition, wxDefaultSize, numSIDevices, SIDevices, 0, wxDefaultValidator);
GCSIDevice[0] = new wxChoice(GamecubePage, ID_GC_SIDEVICE0, wxDefaultPosition, wxDefaultSize, numSIPort1Devices, SIPort1Devices, 0, wxDefaultValidator);
GCSIDevice[1] = new wxChoice(GamecubePage, ID_GC_SIDEVICE1, wxDefaultPosition, wxDefaultSize, numSIDevices, SIDevices, 0, wxDefaultValidator);
GCSIDevice[2] = new wxChoice(GamecubePage, ID_GC_SIDEVICE2, wxDefaultPosition, wxDefaultSize, numSIDevices, SIDevices, 0, wxDefaultValidator);
GCSIDevice[3] = new wxChoice(GamecubePage, ID_GC_SIDEVICE3, wxDefaultPosition, wxDefaultSize, numSIDevices, SIDevices, 0, wxDefaultValidator);
@@ -725,12 +715,6 @@ void CConfigMain::CoreSettingsChanged(wxCommandEvent& event)
SConfig::GetInstance().m_LocalCoreStartupParameter.iTheme = Theme->GetSelection();
main_frame->InitBitmaps();
break;
case ID_INTERFACE_WIIMOTE_LEDS:
SConfig::GetInstance().m_LocalCoreStartupParameter.bWiiLeds = WiimoteStatusLEDs->IsChecked();
break;
case ID_INTERFACE_WIIMOTE_SPEAKERS:
SConfig::GetInstance().m_LocalCoreStartupParameter.bWiiSpeakers = WiimoteStatusSpeakers->IsChecked();
break;
case ID_INTERFACE_LANG:
SConfig::GetInstance().m_InterfaceLanguage = (INTERFACE_LANGUAGE)InterfaceLang->GetSelection();
bRefreshList = true;
-2
View File
@@ -52,7 +52,6 @@ private:
#if wxUSE_TIMER && defined _WIN32
wxCheckBox* HideCursor, *AutoHideCursor;
#endif
wxCheckBox* WiimoteStatusLEDs, * WiimoteStatusSpeakers;
wxChoice* InterfaceLang;
wxChoice* Framelimit;
wxRadioBox* Theme;
@@ -175,7 +174,6 @@ private:
#if wxUSE_TIMER && defined _WIN32
ID_INTERFACE_HIDECURSOR_TEXT, ID_INTERFACE_HIDECURSOR, ID_INTERFACE_AUTOHIDECURSOR,
#endif
ID_INTERFACE_WIIMOTE_TEXT, ID_INTERFACE_WIIMOTE_LEDS, ID_INTERFACE_WIIMOTE_SPEAKERS,
ID_INTERFACE_LANG_TEXT, ID_INTERFACE_LANG,
ID_INTERFACE_THEME,
ID_FRAMELIMIT_TEXT, ID_FRAMELIMIT,
+120 -82
View File
@@ -173,7 +173,7 @@ CPanel::CPanel(
main_frame->bNoWiimoteMsg = false;
else
{
// The Wiimote has been disconnect, we offer reconnect here
// The Wiimote has been disconnected, we offer reconnect here
wxMessageDialog *dlg = new wxMessageDialog(
this,
wxString::Format(wxT("Wiimote %i has been disconnected by system.\n")
@@ -321,7 +321,6 @@ CFrame::CFrame(wxFrame* parent,
, g_pCodeWindow(NULL)
, m_MenuBar(NULL)
, bRenderToMain(false), bNoWiimoteMsg(false)
, HaveLeds(false), HaveSpeakers(false)
, m_ToolBar(NULL), m_ToolBarDebug(NULL), m_ToolBarAui(NULL)
, bFloatLogWindow(false), bFloatConsoleWindow(false)
, m_pStatusBar(NULL), m_GameListCtrl(NULL), m_Panel(NULL)
@@ -523,10 +522,54 @@ void CFrame::OnQuit(wxCommandEvent& WXUNUSED (event))
Close(true);
}
#if defined HAVE_X11 && HAVE_X11
void CFrame::X11_SendClientEvent(const char *message)
{
XEvent event;
Display *dpy = (Display *)Core::GetWindowHandle();
Window win = *(Window *)Core::GetXWindow();
// Init X event structure for client message
event.xclient.type = ClientMessage;
event.xclient.format = 32;
event.xclient.data.l[0] = XInternAtom(dpy, message, False);
// Send the event
if (!XSendEvent(dpy, win, False, False, &event))
ERROR_LOG(VIDEO, "Failed to send message %s to the emulator window.\n", message);
}
void X11_SendKeyEvent(int key)
{
XEvent event;
Display *dpy = (Display *)Core::GetWindowHandle();
Window win = *(Window *)Core::GetXWindow();
// Init X event structure for key press event
event.xkey.type = KeyPress;
// WARNING: This works for '3' to '7'. If in the future other keys are needed
// convert with InputCommon::wxCharCodeWXToX from X11InputBase.cpp.
event.xkey.keycode = XKeysymToKeycode(dpy, key);
// Send the event
if (!XSendEvent(dpy, win, False, False, &event))
ERROR_LOG(VIDEO, "Failed to send key press event to the emulator window.\n");
}
#endif
// --------
// Events
void CFrame::OnActive(wxActivateEvent& event)
{
#if defined(HAVE_X11) && HAVE_X11 && defined(HAVE_GTK2) && HAVE_GTK2 && defined(wxGTK)
if (Core::GetState() == Core::CORE_RUN || Core::GetState() == Core::CORE_PAUSE)
{
if (event.GetActive())
X11_SendClientEvent("FOCUSIN");
else
X11_SendClientEvent("FOCUSOUT");
}
#endif
event.Skip();
}
@@ -582,18 +625,21 @@ void CFrame::OnMove(wxMoveEvent& event)
SConfig::GetInstance().m_LocalCoreStartupParameter.iPosX = GetPosition().x;
SConfig::GetInstance().m_LocalCoreStartupParameter.iPosY = GetPosition().y;
}
void CFrame::OnResize(wxSizeEvent& event)
{
event.Skip();
SConfig::GetInstance().m_LocalCoreStartupParameter.iWidth = GetSize().GetWidth();
SConfig::GetInstance().m_LocalCoreStartupParameter.iHeight = GetSize().GetHeight();
DoMoveIcons(); // In FrameWiimote.cpp
}
void CFrame::OnResizeAll(wxSizeEvent& event)
{
event.Skip();
#if defined(HAVE_X11) && HAVE_X11 && defined(HAVE_GTK2) && HAVE_GTK2 && defined(wxGTK)
if (Core::GetState() == Core::CORE_RUN || Core::GetState() == Core::CORE_PAUSE)
X11_SendClientEvent("RESIZE");
#endif
//wxWindow * Win = (wxWindow*)event.GetEventObject();
//NOTICE_LOG(CONSOLE, "OnResizeAll: %i", (HWND)Win->GetHWND());
}
@@ -649,11 +695,17 @@ void CFrame::OnHostMessage(wxCommandEvent& event)
}
break;
#if defined(HAVE_X11) && HAVE_X11
case WM_USER_CREATE:
bRenderToMain = true;
break;
case TOGGLE_FULLSCREEN:
DoFullscreen(!IsFullScreen());
break;
case WM_USER_STOP:
main_frame->DoStop();
DoStop();
break;
case WM_USER_PAUSE:
main_frame->OnPlay(event);
DoPause();
break;
#endif
}
@@ -740,32 +792,36 @@ void CFrame::OnGameListCtrl_ItemActivated(wxListEvent& WXUNUSED (event))
void CFrame::OnKeyDown(wxKeyEvent& event)
{
// Toggle fullscreen
if (event.GetKeyCode() == WXK_RETURN && event.GetModifiers() == wxMOD_ALT)
{
DoFullscreen(!IsFullScreen());
// We do that to avoid the event to be double processed (which would cause the window to be stuck in fullscreen)
event.StopPropagation();
}
else if(event.GetKeyCode() == WXK_ESCAPE)
{
main_frame->DoPause();
}
// event.Skip() allows the event to propagate to the gamelist for example
else if (! (Core::GetState() == Core::CORE_RUN && bRenderToMain && event.GetEventObject() == this))
event.Skip();
#ifdef _WIN32
if(event.GetKeyCode() == 'M', '3', '4', '5', '6', '7') // Send this to the video plugin WndProc
{
PostMessage((HWND)Core::GetWindowHandle(), WM_USER, WM_USER_KEYDOWN, event.GetKeyCode());
}
#endif
// Send the keyboard status to the Input plugin
if(Core::GetState() != Core::CORE_UNINITIALIZED)
CPluginManager::GetInstance().GetPad(0)->PAD_Input(event.GetKeyCode(), 1); // 1 = Down
{
// Toggle fullscreen
if (event.GetKeyCode() == WXK_RETURN && event.GetModifiers() == wxMOD_ALT)
{
DoFullscreen(!IsFullScreen());
// We do that to avoid the event to be double processed (which would cause the window to be stuck in fullscreen)
event.StopPropagation();
}
else if(event.GetKeyCode() == WXK_ESCAPE)
{
main_frame->DoPause();
}
// event.Skip() allows the event to propagate to the gamelist for example
else if (! (Core::GetState() == Core::CORE_RUN && bRenderToMain && event.GetEventObject() == this))
event.Skip();
if (event.GetKeyCode() >= '3' && event.GetKeyCode() <= '7') // Send this to the video plugin
{
#ifdef _WIN32
PostMessage((HWND)Core::GetWindowHandle(), WM_USER, WM_USER_KEYDOWN, event.GetKeyCode());
#elif defined(HAVE_X11) && HAVE_X11 && defined(HAVE_GTK2) && HAVE_GTK2 && defined(wxGTK)
X11_SendKeyEvent(event.GetKeyCode());
#endif
}
// Send the keyboard status to the Input plugin
CPluginManager::GetInstance().GetPad(0)->PAD_Input(event.GetKeyCode(), 1); // 1 = Down
}
}
void CFrame::OnKeyUp(wxKeyEvent& event)
@@ -910,66 +966,48 @@ wxAuiNotebook* CFrame::CreateEmptyNotebook()
return NB;
}
#if defined HAVE_X11 && HAVE_X11
void X11_ShowFullScreen(bool bF)
{
XEvent event;
Display *dpy = (Display *)Core::GetWindowHandle();
Window win = *(Window *)Core::GetXWindow();
// Init X event structure for TOGGLE_FULLSCREEN client message
event.xclient.type = ClientMessage;
event.xclient.format = 32;
event.xclient.data.l[0] = XInternAtom(dpy, "TOGGLE_FULLSCREEN", False);;
// Send the event
if (!XSendEvent(dpy, win, False, False, &event))
{
ERROR_LOG(VIDEO, "Failed to switch fullscreen/windowed mode.\n");
}
}
#endif
void CFrame::DoFullscreen(bool bF)
{
#if defined HAVE_X11 && HAVE_X11
if ((Core::GetState() == Core::CORE_RUN))
X11_ShowFullScreen(bF);
#endif
// Only switch this to fullscreen if we're rendering to main AND if we're running a game
// plus if a modal dialog is open, this will still process the keyboard events, and may cause
// the main window to become unresponsive, so we have to avoid that.
if ((bRenderToMain && Core::GetState() == Core::CORE_RUN))
if ((Core::GetState() == Core::CORE_RUN) || (Core::GetState() == Core::CORE_PAUSE))
{
ShowFullScreen(bF);
if (bRenderToMain)
{
ShowFullScreen(bF);
if (bF)
{
// Save the current mode before going to fullscreen
AuiCurrent = m_Mgr->SavePerspective();
m_Mgr->LoadPerspective(AuiFullscreen, true);
}
else
{
// Restore saved perspective
m_Mgr->LoadPerspective(AuiCurrent, true);
}
if (bF)
{
// Save the current mode before going to fullscreen
AuiCurrent = m_Mgr->SavePerspective();
m_Mgr->LoadPerspective(AuiFullscreen, true);
}
else
{
// Restore saved perspective
m_Mgr->LoadPerspective(AuiCurrent, true);
}
// Show the cursor again, in case it was hidden
if (IsFullScreen())
{
#ifdef _WIN32
MSWSetCursor(true);
#endif
}
}
#ifdef _WIN32
else // Post the message to the separate rendering window which will then handle it.
{
BringWindowToTop((HWND)Core::GetWindowHandle());
PostMessage((HWND)Core::GetWindowHandle(), WM_USER, TOGGLE_FULLSCREEN, 0);
}
// Show the cursor again, in case it was hidden
if (IsFullScreen())
{
MSWSetCursor(true);
}
#endif
}
#ifdef _WIN32
else // Post the message to the separate rendering window which will then handle it.
{
BringWindowToTop((HWND)Core::GetWindowHandle());
PostMessage((HWND)Core::GetWindowHandle(), WM_USER, TOGGLE_FULLSCREEN, 0);
}
#elif defined HAVE_X11 && HAVE_X11
else // Send the event to the separate rendering window which will then handle it.
X11_SendClientEvent("TOGGLE_FULLSCREEN");
#endif
}
}
// Debugging, show loose windows
@@ -1060,4 +1098,4 @@ void CFrame::ListTopWindows()
j++;
}
NOTICE_LOG(CONSOLE, "\n");
}
}
+5 -25
View File
@@ -64,6 +64,8 @@ class CFrame : public wxFrame
{
#ifdef _WIN32
return(m_Panel->GetHandle());
#elif defined(HAVE_X11) && HAVE_X11
return m_Panel;
#else
return this;
#endif
@@ -91,23 +93,6 @@ class CFrame : public wxFrame
void OnCustomHostMessage(int Id);
void StartGame(const std::string& filename);
// ---------------------------------------
// Wiimote leds
// --------------------
void ModifyStatusBar();
void CreateDestroy(int Case);
void CreateLeds(); void CreateSpeakers();
void UpdateLeds(); void UpdateSpeakers();
wxBitmap CreateBitmapForLeds(bool On);
wxBitmap CreateBitmapForSpeakers(int BitmapType, bool On);
void DoMoveIcons(); void MoveLeds(); void MoveSpeakers();
bool HaveLeds; bool HaveSpeakers;
wxStaticBitmap *m_StatBmp[7];
u8 g_Leds[4]; u8 g_Leds_[4];
u8 g_Speakers[3]; u8 g_Speakers_[3];
// ---------------
// AUI
wxAuiManager *m_Mgr;
wxAuiToolBar *m_ToolBar, *m_ToolBarDebug, *m_ToolBarAui;
@@ -233,14 +218,6 @@ class CFrame : public wxFrame
THEMES_MAX
};
enum WiimoteBitmaps // Wiimote speaker bitmaps
{
CREATELEDS,
DESTROYLEDS,
CREATESPEAKERS,
DESTROYSPEAKERS
};
wxBitmap m_Bitmaps[EToolbar_Max];
wxBitmap m_BitmapsMenu[EToolbar_Max];
@@ -326,6 +303,9 @@ class CFrame : public wxFrame
void OnGameListCtrl_ItemActivated(wxListEvent& event);
void DoFullscreen(bool _F);
#if defined HAVE_X11 && HAVE_X11
void X11_SendClientEvent(const char *message);
#endif
// MenuBar
// File - Drive
+30 -21
View File
@@ -470,6 +470,7 @@ bool game_loading = false;
// 3. Boot last selected game
void CFrame::BootGame(const std::string& filename)
{
bool success = false;
SCoreStartupParameter& StartUp = SConfig::GetInstance().m_LocalCoreStartupParameter;
if (Core::GetState() != Core::CORE_UNINITIALIZED)
@@ -479,23 +480,23 @@ void CFrame::BootGame(const std::string& filename)
// Start the selected ISO, or try one of the saved paths.
// If all that fails, ask to add a dir and don't boot
if (!filename.empty())
BootManager::BootCore(filename);
success = BootManager::BootCore(filename);
else if (m_GameListCtrl->GetSelectedISO() != NULL)
{
if (m_GameListCtrl->GetSelectedISO()->IsValid())
BootManager::BootCore(m_GameListCtrl->GetSelectedISO()->GetFileName());
success = BootManager::BootCore(m_GameListCtrl->GetSelectedISO()->GetFileName());
}
else if (!StartUp.m_strDefaultGCM.empty()
&& wxFileExists(wxString(StartUp.m_strDefaultGCM.c_str(), wxConvUTF8)))
{
BootManager::BootCore(StartUp.m_strDefaultGCM);
success = BootManager::BootCore(StartUp.m_strDefaultGCM);
}
else
{
if (!SConfig::GetInstance().m_LastFilename.empty()
&& wxFileExists(wxString(SConfig::GetInstance().m_LastFilename.c_str(), wxConvUTF8)))
{
BootManager::BootCore(SConfig::GetInstance().m_LastFilename);
success = BootManager::BootCore(SConfig::GetInstance().m_LastFilename);
}
else
{
@@ -506,6 +507,12 @@ void CFrame::BootGame(const std::string& filename)
return;
}
}
if (!success)
{
game_loading = false;
m_GameListCtrl->Enable();
m_GameListCtrl->Show();
}
}
// Open file to boot
@@ -546,13 +553,7 @@ void CFrame::DoOpen(bool Boot)
{
if (!fileChosen)
return;
BootManager::BootCore(std::string(path.mb_str()));
// Game has been started, hide the game list
if (m_GameListCtrl->IsShown())
{
m_GameListCtrl->Disable();
m_GameListCtrl->Hide();
}
StartGame(std::string(path.mb_str()));
}
else
{
@@ -629,16 +630,11 @@ void CFrame::OnPlay(wxCommandEvent& WXUNUSED (event))
wxThread::Sleep(20);
g_pCodeWindow->JumpToAddress(PC);
g_pCodeWindow->Update();
// Update toolbar with Play/Pause status
UpdateGUI();
}
else
{
if (Core::GetState() == Core::CORE_RUN)
Core::SetState(Core::CORE_PAUSE);
else
Core::SetState(Core::CORE_RUN);
}
// Update toolbar with Play/Pause status
UpdateGUI();
DoPause();
}
else
// Core is uninitialized, start the game
@@ -666,7 +662,7 @@ void CFrame::StartGame(const std::string& filename)
void CFrame::OnBootDrive(wxCommandEvent& event)
{
BootManager::BootCore(drives[event.GetId()-IDM_DRIVE1].c_str());
StartGame(drives[event.GetId()-IDM_DRIVE1]);
}
@@ -691,7 +687,20 @@ void CFrame::OnScreenshot(wxCommandEvent& WXUNUSED (event))
// Pause the emulation
void CFrame::DoPause()
{
Core::SetState(Core::CORE_PAUSE);
if (Core::GetState() == Core::CORE_RUN)
{
#if defined(HAVE_X11) && HAVE_X11
X11_SendClientEvent("PAUSE");
#endif
Core::SetState(Core::CORE_PAUSE);
}
else
{
#if defined(HAVE_X11) && HAVE_X11
X11_SendClientEvent("RESUME");
#endif
Core::SetState(Core::CORE_RUN);
}
UpdateGUI();
}
-485
View File
@@ -1,485 +0,0 @@
// 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
// -------------
#include "Globals.h"
#include "Frame.h"
#include "FileUtil.h"
#include "StringUtil.h"
#include "GameListCtrl.h"
#include "BootManager.h"
#include "Common.h"
#include "Setup.h"
#include "ConfigManager.h"
#include "Core.h"
#include "State.h"
#include "ConfigMain.h"
#include "PluginManager.h"
#include "MemcardManager.h"
#include "CheatsWindow.h"
#include "AboutDolphin.h"
#include <wx/statusbr.h>
namespace WiimoteLeds
{
int LED_SIZE_X = 8;
int LED_SIZE_Y = 8;
int SPEAKER_SIZE_X = 8;
int SPEAKER_SIZE_Y = 8;
int ConnectionStatusWidth = 103; // These widths need to be revised, for vista at least
int ConnectionStatusOnlyAdj = 7;
int RightmostMargin = 6;
int SpIconMargin = 11;
int LedIconMargin = 11;
// The necessary recording status width, allow Frame to be at last of the form 100,000
#ifdef RERECORDING
static const int RerecordingStatusWidth = 340;
#endif
// Leds only
static const int LdWidthsOn[] =
{
-1,
#ifdef RERECORDING
RerecordingStatusWidth,
#endif
ConnectionStatusWidth,
(LedIconMargin + LED_SIZE_X) * 4 + RightmostMargin
};
static const int StylesFieldOn[] = { wxSB_NORMAL, wxSB_NORMAL, wxSB_NORMAL };
// Speakers only
static const int SpWidthsOn[] =
{
-1,
#ifdef RERECORDING
RerecordingStatusWidth,
#endif
ConnectionStatusWidth,
( SpIconMargin + SPEAKER_SIZE_X ) * 3 + RightmostMargin
};
static const int SpStylesFieldOn[] = { wxSB_NORMAL,
#ifdef RERECORDING
wxSB_NORMAL,
#endif
wxSB_NORMAL, wxSB_NORMAL };
// Both
static const int LdSpWidthsOn[] =
{
-1,
#ifdef RERECORDING
RerecordingStatusWidth,
#endif
ConnectionStatusWidth,
(SpIconMargin + SPEAKER_SIZE_X) * 3,
(LedIconMargin + LED_SIZE_X) * 4 + RightmostMargin
};
static const int LdSpStylesFieldOn[] = { wxSB_NORMAL,
#ifdef RERECORDING
wxSB_NORMAL,
#endif
wxSB_NORMAL, wxSB_NORMAL };
// Only the Wiimote connection Status
static const int WidthsOff[] =
{
-1,
#ifdef RERECORDING
RerecordingStatusWidth,
#endif
ConnectionStatusWidth + ConnectionStatusOnlyAdj + RightmostMargin
};
static const int StylesFieldOff[] = { wxSB_NORMAL,
#ifdef RERECORDING
wxSB_NORMAL,
#endif
wxSB_NORMAL };
// GC mode
static const int WidthsOffGC[] = { -1
#ifdef RERECORDING
, RerecordingStatusWidth
#endif
};
static const int StylesFieldOffGC[] = { wxSB_NORMAL
#ifdef RERECORDING
, wxSB_NORMAL
#endif
};
};
// =======================================================
// Modify status bar
// -------------
void CFrame::ModifyStatusBar()
{
// Get settings
bool LedsOn = SConfig::GetInstance().m_LocalCoreStartupParameter.bWiiLeds;
bool SpeakersOn = SConfig::GetInstance().m_LocalCoreStartupParameter.bWiiSpeakers;
// Don't use this for GC games, or before a game is loaded
if(!SConfig::GetInstance().m_LocalCoreStartupParameter.bWii)
{ LedsOn = false; SpeakersOn = false; }
// Declarations
int Fields = 0;
int *Widths = 0;
int *StylesFields = 0;
// ---------------------------------------
// Leds only
// -------------
if(LedsOn && !SpeakersOn)
{
Fields = 3;
Widths = (int*)WiimoteLeds::LdWidthsOn;
StylesFields = (int*)WiimoteLeds::StylesFieldOn;
}
// ---------------------------------------
// Speaker only
// -------------
else if(!LedsOn && SpeakersOn)
{
Fields = 3;
Widths = (int*)WiimoteLeds::SpWidthsOn;
StylesFields = (int*)WiimoteLeds::SpStylesFieldOn;
}
// ---------------------------------------
// Both on
// -------------
else if(LedsOn && SpeakersOn)
{
Fields = 4;
Widths = (int*)WiimoteLeds::LdSpWidthsOn;
StylesFields = (int*)WiimoteLeds::LdSpStylesFieldOn;
}
// ---------------------------------------
// Both off
// -------------
else if(!LedsOn && !SpeakersOn)
{
Fields = 2;
Widths = (int*)WiimoteLeds::WidthsOff;
StylesFields = (int*)WiimoteLeds::StylesFieldOff;
// Maybe we should even go down to one field
if(!SConfig::GetInstance().m_LocalCoreStartupParameter.bWii)
{
Fields = 1;
Widths = (int*)WiimoteLeds::WidthsOffGC;
StylesFields = (int*)WiimoteLeds::StylesFieldOffGC;
}
}
// Add a filed for the rerecording status
#ifdef RERECORDING
Fields++;
#endif
// Update the settings
m_pStatusBar->SetFieldsCount(Fields);
m_pStatusBar->SetStatusWidths(Fields, Widths);
m_pStatusBar->SetStatusStyles(Fields, StylesFields);
/* Destroy and create all, and check for HaveLeds and HaveSpeakers in case we have
gotten a confirmed on or off setting, in which case we don't do anything */
if(!LedsOn && HaveLeds) CreateDestroy(DESTROYLEDS);
if(!SpeakersOn && HaveSpeakers) CreateDestroy(DESTROYSPEAKERS);
if(LedsOn && !HaveLeds) CreateDestroy(CREATELEDS);
if(SpeakersOn && !HaveSpeakers) CreateDestroy(CREATESPEAKERS);
DoMoveIcons();
m_pStatusBar->Refresh(); // avoid small glitches that can occur
}
// =======================================================
// Create and destroy leds and speakers icons
// -------------
void CFrame::CreateDestroy(int Case)
{
switch(Case)
{
case CREATELEDS:
{
CreateLeds();
UpdateLeds();
HaveLeds = true;
break;
}
case DESTROYLEDS:
{
for(int i = 0; i < 4; i++)
{
m_StatBmp[i]->Destroy();
}
HaveLeds = false;
break;
}
case CREATESPEAKERS:
{
CreateSpeakers();
HaveSpeakers = true;
break;
}
case DESTROYSPEAKERS:
{
for(int i = 4; i < 7; i++)
{
m_StatBmp[i]->Destroy();
}
HaveSpeakers = false;
break;
}
} // end of switch
DoMoveIcons();
}
// =============
// =======================================================
// Create and update leds
// -------------
void CFrame::CreateLeds()
{
// Begin with blank ones
memset(&g_Leds, 0, sizeof(g_Leds));
for(int i = 0; i < 4; i++)
{
m_StatBmp[i] = new wxStaticBitmap(m_pStatusBar, wxID_ANY,
CreateBitmapForLeds(g_Leds[i] == 1));
}
}
// Update leds
void CFrame::UpdateLeds()
{
for(int i = 0; i < 4; i++)
{
m_StatBmp[i]->SetBitmap(CreateBitmapForLeds(g_Leds[i] != 0));
}
}
// ==============
// =======================================================
// Create and speaker icons
// -------------
void CFrame::CreateSpeakers()
{
// Begin with blank ones
memset(&g_Speakers, 0, sizeof(g_Speakers));
memset(&g_Speakers_, 0, sizeof(g_Speakers_));
for(int i = 0; i < 3; i++)
{
m_StatBmp[i+4] = new wxStaticBitmap(m_pStatusBar, wxID_ANY,
CreateBitmapForSpeakers(i, g_Speakers[i] != 0));
}
}
// Update icons
void CFrame::UpdateSpeakers()
{
/*if(!SConfig::GetInstance().m_LocalCoreStartupParameter.bNTSC)
{ PanicAlert("Not NTSC");}
if(!SConfig::GetInstance().m_LocalCoreStartupParameter.bWii)
{ PanicAlert("Not Wii");}*/
for(int i = 0; i < 3; i++)
{
m_StatBmp[i+4]->SetBitmap(CreateBitmapForSpeakers(i, g_Speakers[i] != 0));
}
}
// ==============
// =======================================================
// Create the Leds bitmap
// -------------
wxBitmap CFrame::CreateBitmapForLeds(bool On)
{
wxBitmap bitmap(WiimoteLeds::LED_SIZE_X, WiimoteLeds::LED_SIZE_Y);
wxMemoryDC dc;
dc.SelectObject(bitmap);
// Set outline and fill colors
wxBrush LightBlueBrush(_T("#0383f0"));
wxPen LightBluePen(_T("#80c5fd"));
wxPen LightGrayPen(_T("#909090"));
dc.SetPen(On ? LightBluePen : LightGrayPen);
dc.SetBrush(On ? LightBlueBrush : *wxWHITE_BRUSH);
dc.Clear();
dc.DrawRectangle(0, 0, WiimoteLeds::LED_SIZE_X, WiimoteLeds::LED_SIZE_Y);
dc.SelectObject(wxNullBitmap);
return bitmap;
}
// =======================================================
// Create the Speaker bitmap
// -------------
wxBitmap CFrame::CreateBitmapForSpeakers(int BitmapType, bool On)
{
wxBitmap bitmap(WiimoteLeds::LED_SIZE_X, WiimoteLeds::LED_SIZE_Y);
wxMemoryDC dc;
dc.SelectObject(bitmap);
wxBrush BackgroundGrayBrush(_T("#ece9d8")); // the right color in windows
switch(BitmapType)
{
case 0: // Speaker on
{
// Set outline and fill colors
dc.SetPen(On ? *wxMEDIUM_GREY_PEN : *wxMEDIUM_GREY_PEN);
dc.SetBrush(On ? *wxGREEN_BRUSH : *wxWHITE_BRUSH);
dc.SetBackground(BackgroundGrayBrush);
dc.Clear();
dc.DrawEllipse(0, 0, WiimoteLeds::SPEAKER_SIZE_X, WiimoteLeds::SPEAKER_SIZE_Y);
dc.SelectObject(wxNullBitmap);
return bitmap;
}
case 1: // Speaker unmuted
{
// Set outline and fill colors
dc.SetPen(On ? *wxMEDIUM_GREY_PEN : *wxMEDIUM_GREY_PEN);
dc.SetBrush(On ? *wxBLUE_BRUSH : *wxWHITE_BRUSH);
dc.SetBackground(BackgroundGrayBrush);
dc.Clear();
dc.DrawEllipse(0, 0, WiimoteLeds::SPEAKER_SIZE_X, WiimoteLeds::SPEAKER_SIZE_Y);
dc.SelectObject(wxNullBitmap);
return bitmap;
}
case 2: // Speaker activity
{
// Set outline and fill colors
dc.SetPen(On ? *wxMEDIUM_GREY_PEN : *wxMEDIUM_GREY_PEN);
dc.SetBrush(On ? *wxGREEN_BRUSH : *wxWHITE_BRUSH);
dc.SetBackground(BackgroundGrayBrush);
dc.Clear();
dc.DrawEllipse(0, 0, WiimoteLeds::SPEAKER_SIZE_X, WiimoteLeds::SPEAKER_SIZE_Y);
dc.SelectObject(wxNullBitmap);
return bitmap;
}
}
return bitmap;
}
// =======================================================
// Move the bitmaps
// -------------
void CFrame::DoMoveIcons()
{
if (!m_pStatusBar) return;
if(HaveLeds) MoveLeds();
if(HaveSpeakers) MoveSpeakers();
// If there is not room for the led icons hide them
if(m_pStatusBar->GetFieldsCount() >= 2 && HaveLeds)
{
wxRect Rect;
#ifdef RERECORDING
m_pStatusBar->GetFieldRect((HaveLeds && HaveSpeakers) ? 4 : 3, Rect);
#else
m_pStatusBar->GetFieldRect((HaveLeds && HaveSpeakers) ? 3 : 2, Rect);
#endif
if(Rect.GetWidth() < 20)
for (int i = 0; i < 4; i++) m_StatBmp[i]->Hide();
else // if(!m_StatBmp[0]->IsShown())
for (int i = 0; i < 4; i++) m_StatBmp[i]->Show();
//INFO_LOG(CONSOLE, "LED: %i ", Rect.GetWidth());
}
// If there is not room for the speaker icons hide them
if(m_pStatusBar->GetFieldsCount() >= 2 && HaveSpeakers)
{
wxRect Rect;
#ifdef RERECORDING
m_pStatusBar->GetFieldRect(3, Rect);
#else
m_pStatusBar->GetFieldRect(2, Rect);
#endif
if(Rect.GetWidth() < 20)
for(int i = 0; i < 3; i++) m_StatBmp[i + 4]->Hide();
else // if(!m_StatBmp[4]->IsShown())
for (int i = 0; i < 3; i++) m_StatBmp[i + 4]->Show();
//INFO_LOG(CONSOLE, "Speaker: %i\n", Rect.GetWidth());
}
}
void CFrame::MoveLeds()
{
wxRect Rect;
// Get the bitmap field coordinates
#ifdef RERECORDING
m_pStatusBar->GetFieldRect((HaveLeds && HaveSpeakers) ? 4 : 3, Rect);
#else
m_pStatusBar->GetFieldRect((HaveLeds && HaveSpeakers) ? 3 : 2, Rect);
#endif
wxSize Size = m_StatBmp[0]->GetSize(); // Get the bitmap size
//wxMessageBox(wxString::Format("%i", Rect.x));
int x = Rect.x + 10;
int Dist = WiimoteLeds::LED_SIZE_X + 7;
int y = Rect.y + (Rect.height - Size.y) / 2;
for(int i = 0; i < 4; i++)
{
if(i > 0) x = m_StatBmp[i-1]->GetPosition().x + Dist;
m_StatBmp[i]->Move(x, y);
}
}
void CFrame::MoveSpeakers()
{
wxRect Rect;
// Get the bitmap field coordinates
#ifdef RERECORDING
m_pStatusBar->GetFieldRect(3, Rect);
#else
m_pStatusBar->GetFieldRect(2, Rect);
#endif
// Get the actual bitmap size, currently it's the same as SPEAKER_SIZE_Y
wxSize Size = m_StatBmp[4]->GetSize();
//wxMessageBox(wxString::Format("%i", Rect.x));
int x = Rect.x + 9;
int Dist = WiimoteLeds::SPEAKER_SIZE_X + 7;
int y = Rect.y + (Rect.height - Size.y) / 2;
for(int i = 0; i < 3; i++)
{
if(i > 0) x = m_StatBmp[i-1+4]->GetPosition().x + Dist;
m_StatBmp[i + 4]->Move(x, y);
}
}
// ==============
+3 -44
View File
@@ -418,7 +418,7 @@ bool DolphinApp::OnInit()
#ifdef DEBUGFAST
const char *title = "Dolphin Debugfast SVN R " SVN_REV_STR;
#else
const char *title = "Dolphin SVN R " SVN_REV_STR;
const char *title = "Dolphin " SVN_REV_STR;
#endif
#endif
@@ -533,6 +533,8 @@ void Host_Message(int Id)
#if defined(HAVE_X11) && HAVE_X11
switch(Id)
{
case WM_USER_CREATE:
case TOGGLE_FULLSCREEN:
case WM_USER_STOP:
case WM_USER_PAUSE:
{
@@ -613,55 +615,12 @@ void Host_UpdateBreakPointView()
}
}
// Update Wiimote status bar
void Host_UpdateLeds(int led_bits)
{
// Convert it to a simpler byte format
main_frame->g_Leds[0] = led_bits >> 0;
main_frame->g_Leds[1] = led_bits >> 1;
main_frame->g_Leds[2] = led_bits >> 2;
main_frame->g_Leds[3] = led_bits >> 3;
main_frame->UpdateLeds();
}
void Host_UpdateSpeakerStatus(int index, int speaker_bits)
{
main_frame->g_Speakers[index] = speaker_bits;
main_frame->UpdateSpeakers();
}
void Host_UpdateStatus()
{
// Debugging
//std::string Tmp = ArrayToString(main_frame->g_Speakers, sizeof(main_frame->g_Speakers));
//std::string Tmp2 = ArrayToString(main_frame->g_Speakers_, sizeof(main_frame->g_Speakers_));
//LOGV(CONSOLE, 0, "Tmp: %s", Tmp.c_str());
//LOGV(CONSOLE, 0, "Tmp2: %s", Tmp2.c_str());
// Don't do a lot of CreateBitmap() if we don't need to
if(memcmp(main_frame->g_Speakers_, main_frame->g_Speakers,
sizeof(main_frame->g_Speakers)))
{
// Turn off the activity light again
main_frame->g_Speakers[2] = 0;
main_frame->UpdateSpeakers();
memcpy(main_frame->g_Speakers_, main_frame->g_Speakers, sizeof(main_frame->g_Speakers));
}
}
void Host_UpdateMemoryView()
{}
void Host_SetDebugMode(bool)
{}
void Host_SetWaitCursor(bool enable)
{
#ifdef _WIN32
+59 -16
View File
@@ -32,6 +32,10 @@
#include <sys/param.h>
#endif
#if defined HAVE_X11 && HAVE_X11
#include <X11/Xlib.h>
#endif
#if defined(HAVE_COCOA) && HAVE_COCOA
#import "cocoaApp.h"
#endif
@@ -54,7 +58,48 @@ void Host_NotifyMapLoaded(){}
void Host_ShowJitResults(unsigned int address){}
void Host_Message(int Id){}
#if defined(HAVE_X11) && HAVE_X11
void X11_SendClientEvent(const char *message)
{
XEvent event;
Display *dpy = (Display *)Core::GetWindowHandle();
Window win = *(Window *)Core::GetXWindow();
// Init X event structure for client message
event.xclient.type = ClientMessage;
event.xclient.format = 32;
event.xclient.data.l[0] = XInternAtom(dpy, message, False);
// Send the event
if (!XSendEvent(dpy, win, False, False, &event))
ERROR_LOG(VIDEO, "Failed to send message %s to the emulator window.\n", message);
}
#endif
Common::Event updateMainFrameEvent;
void Host_Message(int Id)
{
#if defined(HAVE_X11) && HAVE_X11
switch (Id)
{
case WM_USER_STOP:
updateMainFrameEvent.Set();
break;
case WM_USER_PAUSE:
if (Core::GetState() == Core::CORE_RUN)
{
X11_SendClientEvent("PAUSE");
Core::SetState(Core::CORE_PAUSE);
}
else
{
X11_SendClientEvent("RESUME");
Core::SetState(Core::CORE_RUN);
}
break;
}
#endif
}
void Host_UpdateLogDisplay(){}
@@ -62,7 +107,6 @@ void Host_UpdateLogDisplay(){}
void Host_UpdateDisasmDialog(){}
Common::Event updateMainFrameEvent;
void Host_UpdateMainFrame()
{
updateMainFrameEvent.Set();
@@ -99,16 +143,6 @@ void Host_SysMessage(const char *fmt, ...)
fprintf(stderr, "%s", msg);
}
void Host_UpdateLeds(int led_bits)
{
}
void Host_UpdateSpeakerStatus(int index, int speaker_bits)
{
}
void Host_UpdateStatus()
{
}
void Host_SetWiiMoteConnectionState(int _State) {}
@@ -230,7 +264,6 @@ int main(int argc, char* argv[])
std::string bootFile(args_info.inputs[0]);
updateMainFrameEvent.Init();
cpu_info.Detect();
LogManager::Init();
EventHandler::Init();
@@ -239,13 +272,23 @@ int main(int argc, char* argv[])
CPluginManager::GetInstance().ScanForPlugins();
#if defined HAVE_X11 && HAVE_X11
XInitThreads();
#endif
if (BootManager::BootCore(bootFile)) //no use running the loop when booting fails
{
while (PowerPC::GetState() != PowerPC::CPU_POWERDOWN)
{
#if defined(HAVE_X11) && HAVE_X11
while (Core::GetState() == Core::CORE_UNINITIALIZED)
updateMainFrameEvent.Wait();
}
updateMainFrameEvent.Wait();
Core::Stop();
#else
while (PowerPC::GetState() != PowerPC::CPU_POWERDOWN)
updateMainFrameEvent.Wait();
#endif
}
updateMainFrameEvent.Shutdown();
CPluginManager::Shutdown();
SConfig::Shutdown();
+2 -3
View File
@@ -11,8 +11,8 @@ files = [
]
libs = [
'core', 'minilzo', 'discio', 'bdisasm', 'videocommon',
'inputcommon', 'common', 'lua', 'z', 'sfml'
'core', 'lzo2', 'discio', 'bdisasm', 'videocommon',
'inputcommon', 'common', 'lua', 'z', 'sfml-network'
]
if wxenv['HAVE_WX']:
@@ -23,7 +23,6 @@ if wxenv['HAVE_WX']:
'Frame.cpp',
'FrameAui.cpp',
'FrameTools.cpp',
'FrameWiimote.cpp',
'LuaWindow.cpp',
'LogWindow.cpp',
'GameListCtrl.cpp',
@@ -121,9 +121,24 @@ KeySym wxCharCodeWXToX(int id)
void XKeyToString(unsigned int keycode, char *keyStr) {
switch (keycode) {
case XK_Insert:
sprintf(keyStr, "INSERT");
break;
case XK_Delete:
sprintf(keyStr, "DELETE");
break;
case XK_Home:
sprintf(keyStr, "HOME");
break;
case XK_End:
sprintf(keyStr, "END");
break;
case XK_Prior:
sprintf(keyStr, "PAGEUP");
break;
case XK_Next:
sprintf(keyStr, "PAGEDOWN");
break;
case XK_Left:
sprintf(keyStr, "LEFT");
break;
@@ -139,6 +154,18 @@ void XKeyToString(unsigned int keycode, char *keyStr) {
case XK_Return:
sprintf(keyStr, "RETURN");
break;
case XK_Escape:
sprintf(keyStr, "ESCAPE");
break;
case XK_Caps_Lock:
sprintf(keyStr, "CAPSLOCK");
break;
case XK_BackSpace:
sprintf(keyStr, "BACKSPACE");
break;
case XK_Tab:
sprintf(keyStr, "TAB");
break;
case XK_KP_Enter:
sprintf(keyStr, "KP ENTER");
break;
@@ -154,12 +181,114 @@ void XKeyToString(unsigned int keycode, char *keyStr) {
case XK_KP_Down:
sprintf(keyStr, "KP DOWN");
break;
case XK_KP_Insert:
sprintf(keyStr, "KP Insert");
break;
case XK_KP_Delete:
sprintf(keyStr, "KP Delete");
break;
case XK_KP_Page_Down:
sprintf(keyStr, "KP Page Down");
break;
case XK_KP_Page_Up:
sprintf(keyStr, "KP Page Up");
break;
case XK_KP_Separator:
sprintf(keyStr, "KP Separator");
break;
case XK_KP_Home:
sprintf(keyStr, "KP Home");
break;
case XK_KP_End:
sprintf(keyStr, "KP End");
break;
case XK_KP_Subtract:
sprintf(keyStr, "KP -");
break;
case XK_KP_Add:
sprintf(keyStr, "KP +");
break;
case XK_KP_Multiply:
sprintf(keyStr, "KP *");
break;
case XK_KP_Divide:
sprintf(keyStr, "KP /");
break;
case XK_KP_Decimal:
sprintf(keyStr, "KP .");
break;
case XK_KP_0:
sprintf(keyStr, "KP 0");
break;
case XK_KP_1:
sprintf(keyStr, "KP 1");
break;
case XK_KP_2:
sprintf(keyStr, "KP 2");
break;
case XK_KP_3:
sprintf(keyStr, "KP 3");
break;
case XK_KP_4:
sprintf(keyStr, "KP 4");
break;
case XK_KP_5:
sprintf(keyStr, "KP 5");
break;
case XK_KP_6:
sprintf(keyStr, "KP 6");
break;
case XK_KP_7:
sprintf(keyStr, "KP 7");
break;
case XK_KP_8:
sprintf(keyStr, "KP 8");
break;
case XK_KP_9:
sprintf(keyStr, "KP 9");
break;
case XK_Shift_L:
sprintf(keyStr, "LShift");
break;
case XK_Control_L:
sprintf(keyStr, "LControl");
break;
case XK_F1:
sprintf(keyStr, "F1");
break;
case XK_F2:
sprintf(keyStr, "F2");
break;
case XK_F3:
sprintf(keyStr, "F3");
break;
case XK_F4:
sprintf(keyStr, "F4");
break;
case XK_F5:
sprintf(keyStr, "F5");
break;
case XK_F6:
sprintf(keyStr, "F6");
break;
case XK_F7:
sprintf(keyStr, "F7");
break;
case XK_F8:
sprintf(keyStr, "F8");
break;
case XK_F9:
sprintf(keyStr, "F9");
break;
case XK_F10:
sprintf(keyStr, "F10");
break;
case XK_F11:
sprintf(keyStr, "F11");
break;
case XK_F12:
sprintf(keyStr, "F12");
break;
default:
sprintf(keyStr, "%c", toupper(keycode));
}
@@ -20,7 +20,11 @@
#include <cstring>
#include <utility>
#include <algorithm>
#if defined(SHARED_SOIL) && SHARED_SOIL
#include <SOIL/SOIL.h>
#else
#include "SOIL.h"
#endif
#include "CommonPaths.h"
#include "FileUtil.h"
#include "FileSearch.h"
+22
View File
@@ -59,6 +59,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Dolphin", "Core\DolphinWX\D
{823DDC98-42D5-4A38-88CF-9DC06C788AE4} = {823DDC98-42D5-4A38-88CF-9DC06C788AE4}
{3D8156A9-64D1-4C8E-ADBE-1B319030E4A4} = {3D8156A9-64D1-4C8E-ADBE-1B319030E4A4}
{0E231FB1-F3C9-4724-ACCB-DE8BCB3C089E} = {0E231FB1-F3C9-4724-ACCB-DE8BCB3C089E}
{66A4E7BD-E2E8-4373-9B75-8750EB5AE683} = {66A4E7BD-E2E8-4373-9B75-8750EB5AE683}
{E5D1F0C0-AA07-4841-A4EB-4CF4DAA6B0FA} = {E5D1F0C0-AA07-4841-A4EB-4CF4DAA6B0FA}
{29C2ABC1-ADA5-42CD-A5FC-96022D52A510} = {29C2ABC1-ADA5-42CD-A5FC-96022D52A510}
{4D3CD4C5-412B-4B49-9B1B-A68A2A129C77} = {4D3CD4C5-412B-4B49-9B1B-A68A2A129C77}
@@ -193,6 +194,15 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Plugin_GCPad", "Plugins\Plu
{C573CAF7-EE6A-458E-8049-16C0BF34C2E9} = {C573CAF7-EE6A-458E-8049-16C0BF34C2E9}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Plugin_GCPadNew", "Plugins\Plugin_GCPadNew\Plugin_GCPadNew.vcproj", "{1C3A7A91-A97F-4C7C-B45D-26F2242904D7}"
ProjectSection(ProjectDependencies) = postProject
{05C75041-D67D-4903-A362-8395A7B35C75} = {05C75041-D67D-4903-A362-8395A7B35C75}
{11F55366-12EC-4C44-A8CB-1D4E315D61ED} = {11F55366-12EC-4C44-A8CB-1D4E315D61ED}
{0E231FB1-F3C9-4724-ACCB-DE8BCB3C089E} = {0E231FB1-F3C9-4724-ACCB-DE8BCB3C089E}
{1C8436C9-DBAF-42BE-83BC-CF3EC9175ABE} = {1C8436C9-DBAF-42BE-83BC-CF3EC9175ABE}
{C573CAF7-EE6A-458E-8049-16C0BF34C2E9} = {C573CAF7-EE6A-458E-8049-16C0BF34C2E9}
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
@@ -553,6 +563,18 @@ Global
{9FF603F8-B3BB-4144-9688-B2B802FA0F16}.Release|Win32.Build.0 = Release|Win32
{9FF603F8-B3BB-4144-9688-B2B802FA0F16}.Release|x64.ActiveCfg = Release|x64
{9FF603F8-B3BB-4144-9688-B2B802FA0F16}.Release|x64.Build.0 = Release|x64
{1C3A7A91-A97F-4C7C-B45D-26F2242904D7}.Debug|Win32.ActiveCfg = Debug|Win32
{1C3A7A91-A97F-4C7C-B45D-26F2242904D7}.Debug|Win32.Build.0 = Debug|Win32
{1C3A7A91-A97F-4C7C-B45D-26F2242904D7}.Debug|x64.ActiveCfg = Debug|x64
{1C3A7A91-A97F-4C7C-B45D-26F2242904D7}.Debug|x64.Build.0 = Debug|x64
{1C3A7A91-A97F-4C7C-B45D-26F2242904D7}.DebugFast|Win32.ActiveCfg = DebugFast|Win32
{1C3A7A91-A97F-4C7C-B45D-26F2242904D7}.DebugFast|Win32.Build.0 = DebugFast|Win32
{1C3A7A91-A97F-4C7C-B45D-26F2242904D7}.DebugFast|x64.ActiveCfg = DebugFast|x64
{1C3A7A91-A97F-4C7C-B45D-26F2242904D7}.DebugFast|x64.Build.0 = DebugFast|x64
{1C3A7A91-A97F-4C7C-B45D-26F2242904D7}.Release|Win32.ActiveCfg = Release|Win32
{1C3A7A91-A97F-4C7C-B45D-26F2242904D7}.Release|Win32.Build.0 = Release|Win32
{1C3A7A91-A97F-4C7C-B45D-26F2242904D7}.Release|x64.ActiveCfg = Release|x64
{1C3A7A91-A97F-4C7C-B45D-26F2242904D7}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
+3
View File
@@ -35,6 +35,9 @@ typedef struct
{
HWND hWnd;
#if defined HAVE_X11 && HAVE_X11
#if defined(HAVE_GTK2) && HAVE_GTK2
void *pPanel;
#endif
void *pXWindow;
#endif
TLog pLog;
+3
View File
@@ -72,6 +72,9 @@ typedef struct
{
void *pWindowHandle;
#if defined(HAVE_X11) && HAVE_X11
#if defined(HAVE_GTK2) && HAVE_GTK2
void *pPanel;
#endif
void *pXWindow;
#endif
+3
View File
@@ -20,6 +20,9 @@ typedef struct
{
HWND hWnd;
#if defined HAVE_X11 && HAVE_X11
#if defined(HAVE_GTK2) && HAVE_GTK2
void *pPanel;
#endif
void *pXWindow;
#endif
u32 ISOId;
@@ -36,6 +36,7 @@ void CConfig::Load()
file.Load((std::string(File::GetUserPath(D_CONFIG_IDX)) + "DSP.ini").c_str());
file.Get("Config", "EnableHLEAudio", &m_EnableHLEAudio, true); // Sound Settings
file.Get("Config", "EnableRE0AudioFix", &m_EnableRE0Fix, false); // RE0 Hack
m_RE0Fix = m_EnableRE0Fix;
ac_Config.Load(file);
}
@@ -49,3 +50,10 @@ void CConfig::Save()
file.Save((std::string(File::GetUserPath(D_CONFIG_IDX)) + "DSP.ini").c_str());
}
void CConfig::LoadGameIni(const char* gameIniPath)
{
IniFile gameIni;
gameIni.Load(gameIniPath);
gameIni.Get("HLEaudio", "UseRE0Fix", &m_RE0Fix, m_EnableRE0Fix);
}
@@ -23,12 +23,17 @@
struct CConfig
{
bool m_EnableHLEAudio;
//is the RE0 fix enabled in config?
bool m_EnableRE0Fix;
//is the RE0 supposed to be used?
//this value includes game.ini, avoiding overwrite of config
bool m_RE0Fix;
CConfig();
void Load();
void Save();
void LoadGameIni(const char*);
};
extern CConfig g_Config;
@@ -23,6 +23,7 @@
#include "../Globals.h"
#include "Mixer.h"
#include "../MailHandler.h"
#include "../DSPHandler.h"
#include "UCodes.h"
#include "UCode_AXStructs.h"
@@ -65,7 +66,7 @@ static void ProcessUpdates(AXPB &PB)
int on = 0, off = 0;
for (int j = 0; j < numupd; j++)
{
int k = g_Config.m_EnableRE0Fix ? 0 : j;
int k = g_Config.m_RE0Fix ? 0 : j;
const u16 updpar = Memory_Read_U16(updaddr + k);
const u16 upddata = Memory_Read_U16(updaddr + k + 2);
@@ -215,26 +216,43 @@ void CUCode_AX::MixAdd(short* _pBuffer, int _iSize)
// Handle incoming mail
void CUCode_AX::HandleMail(u32 _uMail)
{
if ((_uMail & 0xFFFF0000) == MAIL_AX_ALIST)
{
// We are expected to get a new CmdBlock
DEBUG_LOG(DSPHLE, "GetNextCmdBlock (%ibytes)", (u16)_uMail);
static s8 newucodemails = -1;
if (newucodemails > -1) {
newucodemails++;
if (newucodemails == 10) {
newucodemails = -1;
m_rMailHandler.PushMail(DSP_RESUME);
}
}
else if (_uMail == 0xCDD10000) // Action 0 - restart
{
m_rMailHandler.PushMail(DSP_RESUME);
}
else if (_uMail == 0xCDD10001) // Action 1 - new ucode upload
{
NOTICE_LOG(DSPHLE,"Game wanted to upload new ucode!");
}
else if ((_uMail & 0xFFFF0000) == 0xCDD10000) // Action 2/3
{
}
else
{
DEBUG_LOG(DSPHLE, " >>>> u32 MAIL : AXTask Mail (%08x)", _uMail);
AXTask(_uMail);
else {
if ((_uMail & 0xFFFF0000) == MAIL_AX_ALIST)
{
// We are expected to get a new CmdBlock
DEBUG_LOG(DSPHLE, "GetNextCmdBlock (%ibytes)", (u16)_uMail);
}
else if (_uMail == 0xCDD10000) // Action 0 - AX_ResumeTask();
{
m_rMailHandler.PushMail(DSP_RESUME);
}
else if (_uMail == 0xCDD10001) // Action 1 - new ucode upload ( GC: BayBlade S.T.B,...)
{
NOTICE_LOG(DSPHLE,"DSP IROM - New Ucode!");
newucodemails = 0;
}
else if (_uMail == 0xCDD10002) // Action 2 - IROM_Reset(); ( GC: NFS Carbon, FF Crystal Chronicles,...)
{
NOTICE_LOG(DSPHLE,"DSP IROM - Reset!");
CDSPHandler::GetInstance().SetUCode(UCODE_ROM);
}
else if (_uMail == 0xCDD10003) // Action 3 - AX_GetNextCmdBlock();
{
}
else
{
DEBUG_LOG(DSPHLE, " >>>> u32 MAIL : AXTask Mail (%08x)", _uMail);
AXTask(_uMail);
}
}
}
@@ -19,6 +19,7 @@
#include "../MailHandler.h"
#include "Mixer.h"
#include "../DSPHandler.h"
#include "UCodes.h"
#include "UCode_AXStructs.h"
@@ -50,24 +51,43 @@ CUCode_AXWii::~CUCode_AXWii()
void CUCode_AXWii::HandleMail(u32 _uMail)
{
if ((_uMail & 0xFFFF0000) == MAIL_AX_ALIST)
{
// a new List
static s8 newucodemails = -1;
if (newucodemails > -1) {
newucodemails++;
if (newucodemails == 10) {
newucodemails = -1;
m_rMailHandler.PushMail(DSP_RESUME);
}
}
else if (_uMail == 0xCDD10000) // Action 0 - restart
{
m_rMailHandler.PushMail(DSP_RESUME);
}
else if (_uMail == 0xCDD10001) // Action 1 - new ucode upload
{
NOTICE_LOG(DSPHLE,"Game wanted to upload new ucode!");
}
else if ((_uMail & 0xFFFF0000) == 0xCDD10000) // Action 2/3
{
}
else
{
AXTask(_uMail);
else {
if ((_uMail & 0xFFFF0000) == MAIL_AX_ALIST)
{
// We are expected to get a new CmdBlock
DEBUG_LOG(DSPHLE, "GetNextCmdBlock (%ibytes)", (u16)_uMail);
}
else if (_uMail == 0xCDD10000) // Action 0 - AX_ResumeTask();
{
m_rMailHandler.PushMail(DSP_RESUME);
}
else if (_uMail == 0xCDD10001) // Action 1 - new ucode upload
{
NOTICE_LOG(DSPHLE,"DSP IROM - New Ucode!");
newucodemails = 0;
}
else if (_uMail == 0xCDD10002) // Action 2 - IROM_Reset(); ( WII: De Blob, Cursed Mountain,...)
{
NOTICE_LOG(DSPHLE,"DSP IROM - Reset!");
CDSPHandler::GetInstance().SetUCode(UCODE_ROM);
}
else if (_uMail == 0xCDD10003) // Action 3 - AX_GetNextCmdBlock();
{
}
else
{
DEBUG_LOG(DSPHLE, " >>>> u32 MAIL : AXTask Mail (%08x)", _uMail);
AXTask(_uMail);
}
}
}
+3 -2
View File
@@ -142,8 +142,9 @@ void GetDllInfo(PLUGIN_INFO* _PluginInfo)
void SetDllGlobals(PLUGIN_GLOBALS* _pPluginGlobals)
{
globals = _pPluginGlobals;
LogManager::SetInstance((LogManager *)globals->logManager);
globals = _pPluginGlobals;
LogManager::SetInstance((LogManager *)globals->logManager);
g_Config.LoadGameIni(globals->game_ini);
}
void DllConfig(HWND _hParent)
@@ -129,10 +129,6 @@ GCPadConfigDialog::GCPadConfigDialog(wxWindow *parent, wxWindowID id, const wxSt
#endif
UpdateGUI();
wxTheApp->Connect(wxID_ANY, wxEVT_KEY_DOWN, // Keyboard
wxKeyEventHandler(GCPadConfigDialog::OnKeyDown),
(wxObject*)0, this);
}
GCPadConfigDialog::~GCPadConfigDialog()
@@ -245,10 +241,7 @@ void GCPadConfigDialog::OnKeyDown(wxKeyEvent& event)
SaveButtonMapping(ClickedButton->GetId(), XKey);
#endif
}
m_ButtonMappingTimer->Stop();
GetButtonWaitingTimer = 0;
GetButtonWaitingID = 0;
ClickedButton = NULL;
EndGetButtons();
}
}
@@ -262,6 +255,10 @@ void GCPadConfigDialog::OnButtonClick(wxCommandEvent& event)
if (m_ButtonMappingTimer->IsRunning()) return;
wxTheApp->Connect(wxID_ANY, wxEVT_KEY_DOWN, // Keyboard
wxKeyEventHandler(GCPadConfigDialog::OnKeyDown),
(wxObject*)0, this);
// Create the button object
ClickedButton = (wxButton *)event.GetEventObject();
// Save old label so we can revert back
@@ -235,6 +235,7 @@ class GCPadConfigDialog : public wxDialog
void ToBlank(bool ToBlank, int Id);
void DoGetButtons(int _GetId);
void EndGetButtons();
void SetButtonText(int id, const wxString &str);
wxString GetButtonText(int id);
};
@@ -208,10 +208,7 @@ void GCPadConfigDialog::DoGetButtons(int _GetId)
{
DEBUG_LOG(PAD, "Timer Stopped for Pad:%i _GetId:%i", GCMapping[m_Page].ID, _GetId);
m_ButtonMappingTimer->Stop();
GetButtonWaitingTimer = 0;
GetButtonWaitingID = 0;
ClickedButton = NULL;
EndGetButtons();
}
// If we got a bad button
@@ -227,6 +224,17 @@ void GCPadConfigDialog::DoGetButtons(int _GetId)
}
}
void GCPadConfigDialog::EndGetButtons(void)
{
wxTheApp->Disconnect(wxID_ANY, wxEVT_KEY_DOWN, // Keyboard
wxKeyEventHandler(GCPadConfigDialog::OnKeyDown),
(wxObject*)0, this);
m_ButtonMappingTimer->Stop();
GetButtonWaitingTimer = 0;
GetButtonWaitingID = 0;
ClickedButton = NULL;
}
// Convert the 0x8000 range values to BoxW and BoxH for the plot
void GCPadConfigDialog::Convert2Box(int &x)
{
+5 -3
View File
@@ -658,12 +658,14 @@ bool IsFocus()
return false;
#elif defined HAVE_X11 && HAVE_X11
Window GLWin = *(Window *)g_PADInitialize->pXWindow;
bool bFocus = False;
#if defined(HAVE_GTK2) && HAVE_GTK2 && defined(wxGTK)
bFocus = (wxPanel *)g_PADInitialize->pPanel == wxWindow::FindFocus();
#endif
Window FocusWin;
int Revert;
XGetInputFocus(GCdisplay, &FocusWin, &Revert);
XWindowAttributes WinAttribs;
XGetWindowAttributes (GCdisplay, GLWin, &WinAttribs);
return (GLWin != 0 && (GLWin == FocusWin || WinAttribs.override_redirect));
return (GLWin == FocusWin || bFocus);
#else
return true;
#endif
@@ -0,0 +1,660 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9.00"
Name="Plugin_GCPadNew"
ProjectGUID="{1C3A7A91-A97F-4C7C-B45D-26F2242904D7}"
RootNamespace="Plugin_GCPadNew"
Keyword="Win32Proj"
TargetFrameworkVersion="131072"
>
<Platforms>
<Platform
Name="Win32"
/>
<Platform
Name="x64"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(PlatformName)\$(ConfigurationName)"
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
ConfigurationType="2"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="..\..\PluginSpecs;..\..\..\Externals\SDL\Include;..\..\Core\Common\Src;..\..\..\Externals\wxWidgets\Include;..\..\..\Externals\wxWidgets\Include\msvc"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;PLUGIN_NJOY_SDL_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_SECURE_SCL=0"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
UsePrecompiledHeader="0"
WarningLevel="3"
WarnAsError="false"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="comctl32.lib rpcrt4.lib xinput.lib winmm.lib wxbase28ud.lib wxmsw28ud_core.lib"
OutputFile="..\..\..\Binary\Win32\Plugins\$(ProjectName)D.dll"
LinkIncremental="2"
AdditionalLibraryDirectories="..\..\..\Externals\SDL\win32;..\..\..\Externals\wxWidgets\lib\vc_lib\Win32"
GenerateManifest="false"
GenerateDebugInformation="true"
ProgramDatabaseFile="$(PlatformName)\$(ConfigurationName)\$(TargetName).pdb"
SubSystem="2"
RandomizedBaseAddress="1"
DataExecutionPrevention="0"
ImportLibrary="$(PlatformName)\$(ConfigurationName)\$(TargetName).lib"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Debug|x64"
OutputDirectory="$(PlatformName)\$(ConfigurationName)"
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
ConfigurationType="2"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
TargetEnvironment="3"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="..\..\PluginSpecs;..\..\..\Externals\SDL\Include;..\..\Core\Common\Src;..\..\..\Externals\wxWidgets\Include;..\..\..\Externals\wxWidgets\Include\msvc"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;PLUGIN_NJOY_SDL_EXPORTS;_SECURE_SCL=0;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
UsePrecompiledHeader="0"
WarningLevel="3"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="comctl32.lib rpcrt4.lib xinput.lib winmm.lib wxbase28ud.lib wxmsw28ud_core.lib"
OutputFile="..\..\..\Binary\x64\Plugins\$(ProjectName)D.dll"
LinkIncremental="2"
AdditionalLibraryDirectories="..\..\..\Externals\SDL\x64;..\..\..\Externals\wxWidgets\lib\vc_lib\x64"
GenerateManifest="false"
GenerateDebugInformation="true"
ProgramDatabaseFile="$(PlatformName)\$(ConfigurationName)\$(TargetName).pdb"
SubSystem="2"
RandomizedBaseAddress="1"
DataExecutionPrevention="0"
ImportLibrary="$(PlatformName)\$(ConfigurationName)\$(TargetName).lib"
TargetMachine="17"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(PlatformName)\$(ConfigurationName)"
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
ConfigurationType="2"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="..\..\PluginSpecs;..\..\..\Externals\SDL\Include;..\..\Core\Common\Src;..\..\..\Externals\wxWidgets\Include;..\..\..\Externals\wxWidgets\Include\msvc"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;PLUGIN_NJOY_SDL_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_SECURE_SCL=0"
RuntimeLibrary="0"
UsePrecompiledHeader="0"
WarningLevel="3"
WarnAsError="false"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="comctl32.lib xinput.lib winmm.lib wxbase28u.lib wxmsw28u_core.lib"
OutputFile="..\..\..\Binary\Win32\Plugins\$(ProjectName).dll"
LinkIncremental="1"
AdditionalLibraryDirectories="..\..\..\Externals\SDL\win32;..\..\..\Externals\wxWidgets\lib\vc_lib\Win32"
GenerateManifest="false"
GenerateDebugInformation="true"
ProgramDatabaseFile="$(PlatformName)\$(ConfigurationName)\$(TargetName).pdb"
SubSystem="2"
OptimizeReferences="2"
EnableCOMDATFolding="2"
RandomizedBaseAddress="1"
DataExecutionPrevention="0"
ImportLibrary="$(PlatformName)\$(ConfigurationName)\$(TargetName).lib"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|x64"
OutputDirectory="$(PlatformName)\$(ConfigurationName)"
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
ConfigurationType="2"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
TargetEnvironment="3"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="2"
InlineFunctionExpansion="2"
EnableIntrinsicFunctions="true"
FavorSizeOrSpeed="1"
WholeProgramOptimization="false"
AdditionalIncludeDirectories="..\..\PluginSpecs;..\..\..\Externals\SDL\Include;..\..\Core\Common\Src;..\..\..\Externals\wxWidgets\Include;..\..\..\Externals\wxWidgets\Include\msvc"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;PLUGIN_NJOY_SDL_EXPORTS;_SECURE_SCL=0;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE"
RuntimeLibrary="0"
UsePrecompiledHeader="0"
WarningLevel="3"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="comctl32.lib xinput.lib winmm.lib wxbase28u.lib wxmsw28u_core.lib"
OutputFile="..\..\..\Binary\x64\Plugins\$(ProjectName).dll"
LinkIncremental="1"
AdditionalLibraryDirectories="..\..\..\Externals\SDL\x64;..\..\..\Externals\wxWidgets\lib\vc_lib\x64"
GenerateManifest="false"
GenerateDebugInformation="true"
ProgramDatabaseFile="$(PlatformName)\$(ConfigurationName)\$(TargetName).pdb"
SubSystem="2"
OptimizeReferences="2"
EnableCOMDATFolding="2"
RandomizedBaseAddress="1"
DataExecutionPrevention="0"
ImportLibrary="$(PlatformName)\$(ConfigurationName)\$(TargetName).lib"
TargetMachine="17"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="DebugFast|Win32"
OutputDirectory="$(PlatformName)\$(ConfigurationName)"
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
ConfigurationType="2"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="..\..\PluginSpecs;..\..\..\Externals\SDL\Include;..\..\Core\Common\Src;..\..\..\Externals\wxWidgets\Include;..\..\..\Externals\wxWidgets\Include\msvc"
PreprocessorDefinitions="WIN32;NDEBUG;DEBUGFAST;_WINDOWS;_USRDLL;PLUGIN_NJOY_SDL_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_SECURE_SCL=0"
RuntimeLibrary="0"
UsePrecompiledHeader="0"
WarningLevel="3"
WarnAsError="false"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="comctl32.lib rpcrt4.lib xinput.lib winmm.lib wxbase28u.lib wxmsw28u_core.lib"
OutputFile="..\..\..\Binary\Win32\Plugins\$(ProjectName)DF.dll"
LinkIncremental="1"
AdditionalLibraryDirectories="..\..\..\Externals\SDL\win32;..\..\..\Externals\wxWidgets\lib\vc_lib\Win32"
GenerateManifest="false"
GenerateDebugInformation="true"
ProgramDatabaseFile="$(PlatformName)\$(ConfigurationName)\$(TargetName).pdb"
SubSystem="2"
OptimizeReferences="2"
EnableCOMDATFolding="2"
RandomizedBaseAddress="1"
DataExecutionPrevention="0"
ImportLibrary="$(PlatformName)\$(ConfigurationName)\$(TargetName).lib"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="DebugFast|x64"
OutputDirectory="$(PlatformName)\$(ConfigurationName)"
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
ConfigurationType="2"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
TargetEnvironment="3"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="..\..\PluginSpecs;..\..\..\Externals\SDL\Include;..\..\Core\Common\Src;..\..\..\Externals\wxWidgets\Include;..\..\..\Externals\wxWidgets\Include\msvc"
PreprocessorDefinitions="WIN32;NDEBUG;DEBUGFAST;_WINDOWS;_USRDLL;PLUGIN_NJOY_SDL_EXPORTS;_SECURE_SCL=0;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE"
RuntimeLibrary="0"
UsePrecompiledHeader="0"
WarningLevel="3"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="comctl32.lib rpcrt4.lib xinput.lib winmm.lib wxbase28u.lib wxmsw28u_core.lib"
OutputFile="..\..\..\Binary\x64\Plugins\$(ProjectName)DF.dll"
LinkIncremental="1"
AdditionalLibraryDirectories="..\..\..\Externals\SDL\x64;..\..\..\Externals\wxWidgets\lib\vc_lib\x64"
GenerateManifest="false"
GenerateDebugInformation="true"
ProgramDatabaseFile="$(PlatformName)\$(ConfigurationName)\$(TargetName).pdb"
SubSystem="2"
OptimizeReferences="2"
EnableCOMDATFolding="2"
RandomizedBaseAddress="1"
DataExecutionPrevention="0"
ImportLibrary="$(PlatformName)\$(ConfigurationName)\$(TargetName).lib"
TargetMachine="17"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Config"
>
<File
RelativePath=".\Src\Config.cpp"
>
</File>
<File
RelativePath=".\Src\Config.h"
>
</File>
<Filter
Name="GUI"
>
<File
RelativePath=".\Src\ConfigDiag.cpp"
>
</File>
<File
RelativePath=".\Src\ConfigDiag.h"
>
</File>
<File
RelativePath=".\Src\ConfigDiagBitmaps.cpp"
>
</File>
</Filter>
</Filter>
<Filter
Name="IniFile"
>
<File
RelativePath=".\Src\IniFile.cpp"
>
</File>
<File
RelativePath=".\Src\IniFile.h"
>
</File>
</Filter>
<Filter
Name="ControllerInterface"
>
<File
RelativePath=".\Src\ControllerInterface\ControllerInterface.cpp"
>
</File>
<File
RelativePath=".\Src\ControllerInterface\ControllerInterface.h"
>
</File>
<Filter
Name="XInput"
>
<File
RelativePath=".\Src\ControllerInterface\XInput\XInput.cpp"
>
</File>
<File
RelativePath=".\Src\ControllerInterface\XInput\XInput.h"
>
</File>
</Filter>
<Filter
Name="SDL"
>
<File
RelativePath=".\Src\ControllerInterface\SDL\SDL.cpp"
>
</File>
<File
RelativePath=".\Src\ControllerInterface\SDL\SDL.h"
>
</File>
</Filter>
<Filter
Name="DirectInput"
>
<File
RelativePath=".\Src\ControllerInterface\DirectInput\DirectInput.cpp"
>
</File>
<File
RelativePath=".\Src\ControllerInterface\DirectInput\DirectInput.h"
>
</File>
<File
RelativePath=".\Src\ControllerInterface\DirectInput\DirectInputJoystick.cpp"
>
</File>
<File
RelativePath=".\Src\ControllerInterface\DirectInput\DirectInputJoystick.h"
>
</File>
<File
RelativePath=".\Src\ControllerInterface\DirectInput\DirectInputKeyboardMouse.cpp"
>
</File>
<File
RelativePath=".\Src\ControllerInterface\DirectInput\DirectInputKeyboardMouse.h"
>
</File>
<File
RelativePath=".\Src\ControllerInterface\DirectInput\NamedKeys.h"
>
</File>
</Filter>
</Filter>
<Filter
Name="ControllerEmu"
>
<File
RelativePath=".\Src\ControllerEmu.cpp"
>
</File>
<File
RelativePath=".\Src\ControllerEmu.h"
>
</File>
<Filter
Name="GCPad"
>
<File
RelativePath=".\Src\ControllerEmu\GCPad\GCPad.cpp"
>
</File>
<File
RelativePath=".\Src\ControllerEmu\GCPad\GCPad.h"
>
</File>
</Filter>
</Filter>
<File
RelativePath=".\Src\GCPadNew.cpp"
>
</File>
<File
RelativePath=".\Src\SConscript"
>
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>
@@ -0,0 +1,51 @@
#include "Config.h"
Plugin::Plugin()
{
// GCPads
for ( unsigned int i = 0; i<4; ++i )
controllers.push_back( new GCPad( i ) );
};
Plugin::~Plugin()
{
// delete pads
std::vector<ControllerEmu*>::const_iterator i = controllers.begin(),
e = controllers.end();
for ( ; i != e; ++i )
delete *i;
}
void Plugin::LoadConfig()
{
IniFile inifile;
std::ifstream file;
file.open( (std::string(File::GetUserPath(D_CONFIG_IDX)) + CONFIG_FILE_NAME ).c_str() );
inifile.Load( file );
file.close();
std::vector< ControllerEmu* >::const_iterator i = controllers.begin(),
e = controllers.end();
for ( ; i!=e; ++i )
(*i)->LoadConfig( inifile[ (*i)->GetName() ] );
}
void Plugin::SaveConfig()
{
IniFile inifile;
std::vector< ControllerEmu* >::const_iterator i = controllers.begin(),
e = controllers.end();
for ( ; i!=e; ++i )
(*i)->SaveConfig( inifile[ (*i)->GetName() ] );
// dont need to save empty values
inifile.Clean();
std::ofstream file;
file.open( (std::string(File::GetUserPath(D_CONFIG_IDX)) + CONFIG_FILE_NAME ).c_str() );
inifile.Save( file );
file.close();
}
@@ -0,0 +1,35 @@
#ifndef _CONFIG_H_
#define _CONFIG_H_
#define CONFIG_FILE_NAME "GCPadNew.ini"
#include "ControllerInterface/ControllerInterface.h"
#include "Thread.h"
#include "FileUtil.h"
#include "IniFile.h"
#include "ControllerEmu.h"
#include "ControllerEmu/GCPad/GCPad.h"
#include <string>
#include <vector>
#include <map>
#include <sstream>
class Plugin
{
public:
Plugin();
~Plugin();
void LoadConfig();
void SaveConfig();
std::vector< ControllerEmu* > controllers;
Common::CriticalSection controls_crit, interface_crit; // lock controls first
ControllerInterface controller_interface;
};
#endif
@@ -0,0 +1,833 @@
#include "ConfigDiag.h"
PadSettingCheckBox::PadSettingCheckBox( wxWindow* const parent, ControlState& _value, const char* const label )
: PadSetting(_value)
, wxCheckBox( parent, -1, wxString::FromAscii( label ), wxDefaultPosition )
{
UpdateGUI();
}
void PadSettingCheckBox::UpdateGUI()
{
SetValue( value > 0 );
}
void PadSettingCheckBox::UpdateValue()
{
// 0.01 so its saved to the ini file as just 1. :(
value = 0.01 * GetValue();
}
PadSettingChoice::PadSettingChoice( wxWindow* const parent, ControlState& _value, int min, int max )
: PadSetting(_value)
, wxChoice( parent, -1, wxDefaultPosition, wxSize( 48, -1 ) )
{
Append( wxT("0") );
for ( ; min<=max; ++min )
{
std::ostringstream ss;
ss << min;
Append( wxString::FromAscii( ss.str().c_str() ) );
}
UpdateGUI();
}
void PadSettingChoice::UpdateGUI()
{
std::ostringstream ss;
ss << int(value * 100);
SetSelection( FindString( wxString::FromAscii( ss.str().c_str() ) ) );
}
void PadSettingChoice::UpdateValue()
{
value = float( atoi( GetStringSelection().mb_str() ) ) / 100;
}
ControlDialog::ControlDialog( wxWindow* const parent, ControllerInterface::ControlReference* const ref, const std::vector<ControllerInterface::Device*>& devs )
:wxDialog( parent, -1, wxT("Configure Control"), wxDefaultPosition )
,control_reference(ref)
{
device_cbox = new wxComboBox( this, -1, wxString::FromAscii( ref->device_qualifier.ToString().c_str() ), wxDefaultPosition, wxSize(256,-1), wxArrayString(), wxTE_PROCESS_ENTER );
#define _connect_macro2_( b, f, c ) (b)->Connect( wxID_ANY, c, wxCommandEventHandler( GamepadPage::f ), (wxObject*)0, (wxEvtHandler*)parent );
_connect_macro2_( device_cbox, SetDevice, wxEVT_COMMAND_COMBOBOX_SELECTED );
_connect_macro2_( device_cbox, SetDevice, wxEVT_COMMAND_TEXT_ENTER );
std::vector< ControllerInterface::Device* >::const_iterator i = devs.begin(),
e = devs.end();
ControllerInterface::DeviceQualifier dq;
for ( ; i!=e; ++i )
{
dq.FromDevice( *i );
device_cbox->Append( wxString::FromAscii( dq.ToString().c_str() ) );
}
control_chooser = new ControlChooser( this, ref, parent );
wxStaticBoxSizer* d_szr = new wxStaticBoxSizer( wxVERTICAL, this, wxT("Device") );
d_szr->Add( device_cbox, 0, wxEXPAND|wxALL, 5 );
wxBoxSizer* szr = new wxBoxSizer( wxVERTICAL );
szr->Add( d_szr, 0, wxEXPAND|wxLEFT|wxRIGHT|wxTOP, 5 );
szr->Add( control_chooser, 0, wxEXPAND|wxALL, 5 );
SetSizerAndFit( szr );
}
ControlButton::ControlButton( wxWindow* const parent, ControllerInterface::ControlReference* const _ref, const unsigned int width, const std::string& label )
: wxButton( parent, -1, wxT(""), wxDefaultPosition, wxSize( width,20) )
, control_reference( _ref )
{
if ( label.empty() )
SetLabel( wxString::FromAscii( _ref->control_qualifier.name.c_str() ) );
else
SetLabel( wxString::FromAscii( label.c_str() ) );
}
void ConfigDialog::UpdateProfileComboBox()
{
std::string pname( File::GetUserPath(D_CONFIG_IDX) );
pname += PROFILES_PATH;
CFileSearch::XStringVector exts;
exts.push_back("*.ini");
CFileSearch::XStringVector dirs;
dirs.push_back( pname );
CFileSearch cfs( exts, dirs );
const CFileSearch::XStringVector& sv = cfs.GetFileNames();
wxArrayString strs;
CFileSearch::XStringVector::const_iterator si = sv.begin(),
se = sv.end();
for ( ; si!=se; ++si )
{
std::string str( si->begin() + si->find_last_of('/') + 1 , si->end() - 4 ) ;
strs.push_back( wxString::FromAscii( str.c_str() ) );
}
std::vector< GamepadPage* >::iterator i = m_padpages.begin(),
e = m_padpages.end();
for ( ; i != e; ++i )
{
(*i)->profile_cbox->Clear();
(*i)->profile_cbox->Append(strs);
}
}
void ConfigDialog::UpdateControlReferences()
{
std::vector< GamepadPage* >::iterator i = m_padpages.begin(),
e = m_padpages.end();
for ( ; i != e; ++i )
(*i)->controller->UpdateReferences( m_plugin.controller_interface );
}
void ConfigDialog::ClickSave( wxCommandEvent& event )
{
m_plugin.SaveConfig();
Close();
};
void ControlChooser::UpdateGUI()
{
control_lbox->Clear();
// make sure it's a valid device
if ( control_reference->device )
{
if ( control_reference->is_input )
{
// for inputs
std::vector<ControllerInterface::Device::Input*>::const_iterator
i = control_reference->device->Inputs().begin(),
e = control_reference->device->Inputs().end();
for ( ; i!=e; ++i )
control_lbox->Append( wxString::FromAscii( (*i)->GetName().c_str() ) );
}
else
{
// for outputs
std::vector<ControllerInterface::Device::Output*>::const_iterator
i = control_reference->device->Outputs().begin(),
e = control_reference->device->Outputs().end();
for ( ; i!=e; ++i )
control_lbox->Append( wxString::FromAscii( (*i)->GetName().c_str() ) );
}
}
// logic not 100% right here for a poorly formated qualifier
// but its just for selecting crap in the listbox
wxArrayString control_names = control_lbox->GetStrings();
const std::string cname = control_reference->control_qualifier.name;
for ( int i = int(control_names.size()) - 1; i >=0; --i )
{
if ( cname == std::string(control_names[i].ToAscii()) ||
cname.find( control_names[i].Prepend(wxT('|')).Append(wxT('|')).ToAscii() ) != std::string::npos )
control_lbox->Select( i );
else
control_lbox->Deselect( i );
}
size_t bound = control_reference->controls.size();
std::ostringstream ss;
ss << "Bound Controls: ";
if ( bound ) ss << bound; else ss << "None";
m_bound_label->SetLabel( wxString::FromAscii(ss.str().c_str()) );
textctrl->SetValue( wxString::FromAscii( control_reference->control_qualifier.name.c_str() ) );
};
void GamepadPage::UpdateGUI()
{
device_cbox->SetLabel( wxString::FromAscii( controller->default_device.ToString().c_str() ) );
std::vector< ControlGroupBox* >::const_iterator
g = control_groups.begin(),
ge = control_groups.end();
for ( ; g!=ge; ++g )
{
// buttons
std::vector<ControlButton*>::const_iterator
i = (*g)->control_buttons.begin(),
e = (*g)->control_buttons.end();
for ( ; i!=e; ++i )
(*i)->SetLabel( wxString::FromAscii( (*i)->control_reference->control_qualifier.name.c_str() ) );
// settings
std::vector<PadSetting*>::const_iterator
si = (*g)->options.begin(),
se = (*g)->options.end();
for ( ; si!=se; ++si )
(*si)->UpdateGUI();
}
}
void GamepadPage::ClearAll( wxCommandEvent& event )
{
m_plugin.controls_crit.Enter(); // enter
// just load an empty ini section to clear everything :P
IniSection Section = IniSection();
ControllerInterface Face = ControllerInterface();
controller->LoadConfig( Section );
// no point in using the real ControllerInterface i guess
controller->UpdateReferences( Face );
UpdateGUI();
m_plugin.controls_crit.Leave(); // leave
}
void GamepadPage::SetControl( wxCommandEvent& event )
{
m_plugin.controls_crit.Enter(); // enter
m_control_dialog->control_reference->control_qualifier.name = std::string( m_control_dialog->control_chooser->textctrl->GetValue().ToAscii() );
m_control_dialog->control_reference->UpdateControls();
m_control_dialog->control_chooser->UpdateGUI();
UpdateGUI();
m_plugin.controls_crit.Leave(); // leave
}
void GamepadPage::SetDevice( wxCommandEvent& event )
{
m_plugin.controls_crit.Enter(); // enter
// TODO: need to handle the ConfigControl device in here
// default device
if ( event.GetEventObject() == device_cbox )
{
controller->default_device.FromString( std::string( device_cbox->GetValue().ToAscii() ) );
// show user what it was validated as
device_cbox->SetValue( wxString::FromAscii( controller->default_device.ToString().c_str() ) );
// this will set all the controls to this default device
controller->UpdateDefaultDevice();
// update references
controller->UpdateReferences( m_plugin.controller_interface );
}
// control dialog
else
{
m_control_dialog->control_reference->device_qualifier.FromString( std::string( m_control_dialog->device_cbox->GetValue().ToAscii() ) );
m_control_dialog->device_cbox->SetValue( wxString::FromAscii( m_control_dialog->control_reference->device_qualifier.ToString().c_str() ) );
m_plugin.controller_interface.UpdateReference( m_control_dialog->control_reference );
m_control_dialog->control_chooser->UpdateGUI();
}
m_plugin.controls_crit.Leave(); // leave
}
void GamepadPage::ClearControl( wxCommandEvent& event )
{
m_control_dialog->control_reference->control_qualifier.name.clear();
m_control_dialog->control_reference->UpdateControls();
m_control_dialog->control_chooser->UpdateGUI();
UpdateGUI();
}
void GamepadPage::AdjustSetting( wxCommandEvent& event )
{
m_plugin.controls_crit.Enter(); // enter
// updates the setting value from the GUI control
(dynamic_cast<PadSetting*>(event.GetEventObject()))->UpdateValue();
m_plugin.controls_crit.Leave(); // leave
}
void GamepadPage::AdjustControlOption( wxCommandEvent& event )
{
m_plugin.controls_crit.Enter(); // enter
m_control_dialog->control_reference->range = ControlState( m_control_dialog->control_chooser->range_slider->GetValue() ) / SLIDER_TICK_COUNT;
if ( m_control_dialog->control_reference->is_input )
{
((ControllerInterface::InputReference*)m_control_dialog->control_reference)->mode = m_control_dialog->control_chooser->mode_cbox->GetSelection();
}
m_plugin.controls_crit.Leave(); // leave
}
void GamepadPage::ConfigControl( wxCommandEvent& event )
{
m_control_dialog = new ControlDialog( this, ((ControlButton*)event.GetEventObject())->control_reference, m_plugin.controller_interface.Devices() );
m_control_dialog->ShowModal();
m_control_dialog->Destroy();
}
void GamepadPage::ConfigDetectControl( wxCommandEvent& event )
{
m_plugin.controls_crit.Enter(); // enter
// major major hacks
wxChar num = ((wxButton*)event.GetEventObject())->GetLabel()[0];
if ( num > '9' )
num = 1;
else
num -= 0x30;
if ( m_control_dialog->control_reference->Detect( DETECT_WAIT_TIME, num ) ) // if we got input, update control
{
UpdateGUI();
m_control_dialog->control_chooser->UpdateGUI();
}
m_plugin.controls_crit.Leave(); // leave
}
void GamepadPage::DetectControl( wxCommandEvent& event )
{
ControlButton* btn = (ControlButton*)event.GetEventObject();
m_plugin.controls_crit.Enter(); // enter
btn->control_reference->Detect( DETECT_WAIT_TIME );
btn->SetLabel( wxString::FromAscii( btn->control_reference->control_qualifier.name.c_str() ) );
m_plugin.controls_crit.Leave(); // leave
}
void ControlDialog::SelectControl( wxCommandEvent& event )
{
wxListBox* lb = (wxListBox*)event.GetEventObject();
wxArrayInt sels;
lb->GetSelections( sels );
wxArrayString names = lb->GetStrings();
wxString final_label;
if ( sels.size() == 1 )
final_label = names[ sels[0] ];
//else if ( sels.size() == lb->GetCount() )
// final_label = "||";
else
{
final_label = wxT('|');
for ( unsigned int i=0; i<sels.size(); ++i )
final_label += names[ sels[i] ] + wxT('|');
}
if (!final_label.CompareTo(wxT("|")))
final_label.Empty();
#ifdef __linux__
if (!((wxWindow*)this)->IsBeingDeleted())
#endif
control_chooser->textctrl->SetValue( final_label );
#ifndef __linux__ // This causes the application to hang in linux
// kinda dumb
wxCommandEvent nullevent;
((GamepadPage*)m_parent)->SetControl( nullevent );
#endif
}
ControlChooser::ControlChooser( wxWindow* const parent, ControllerInterface::ControlReference* const ref, wxWindow* const eventsink )
: wxStaticBoxSizer( wxVERTICAL, parent, ref->is_input ? wxT("Input") : wxT("Output") )
, control_reference(ref)
{
#define _connect_macro_( b, f, c ) (b)->Connect( wxID_ANY, (c), wxCommandEventHandler( GamepadPage::f ), (wxObject*)0, (wxEvtHandler*)eventsink );
textctrl = new wxTextCtrl( parent, -1 );
wxButton* detect_button = new wxButton( parent, -1, ref->is_input ? wxT("Detect 1") : wxT("Test") );
wxButton* clear_button = new wxButton( parent, -1, wxT("Clear"), wxDefaultPosition );
wxButton* set_button = new wxButton( parent, -1, wxT("Set")/*, wxDefaultPosition, wxSize( 32, -1 )*/ );
control_lbox = new wxListBox( parent, -1, wxDefaultPosition, wxSize( 256, 128 ), wxArrayString(), wxLB_EXTENDED );
control_lbox->Connect( wxID_ANY, wxEVT_COMMAND_LISTBOX_SELECTED, wxCommandEventHandler( ControlDialog::SelectControl ), (wxObject*)0, parent );
wxBoxSizer* button_sizer = new wxBoxSizer( wxHORIZONTAL );
button_sizer->Add( detect_button, 1, 0, 5 );
if ( ref->is_input )
for ( unsigned int i = 2; i<5; ++i )
{
wxButton* d_btn = new wxButton( parent, -1, wxChar( '0'+i ), wxDefaultPosition, wxSize(16,-1) );
_connect_macro_( d_btn, ConfigDetectControl, wxEVT_COMMAND_BUTTON_CLICKED);
button_sizer->Add( d_btn );
}
button_sizer->Add( clear_button, 1, 0, 5 );
button_sizer->Add( set_button, 1, 0, 5 );
range_slider = new wxSlider( parent, -1, SLIDER_TICK_COUNT, 0, SLIDER_TICK_COUNT, wxDefaultPosition, wxDefaultSize, wxSL_TOP | wxSL_LABELS /*| wxSL_AUTOTICKS*/ );
range_slider->SetValue( control_reference->range * SLIDER_TICK_COUNT );
_connect_macro_( detect_button, ConfigDetectControl, wxEVT_COMMAND_BUTTON_CLICKED);
_connect_macro_( clear_button, ClearControl, wxEVT_COMMAND_BUTTON_CLICKED);
_connect_macro_( set_button, SetControl, wxEVT_COMMAND_BUTTON_CLICKED);
_connect_macro_( range_slider, AdjustControlOption, wxEVT_SCROLL_CHANGED);
wxStaticText* range_label = new wxStaticText( parent, -1, wxT("Range"));
m_bound_label = new wxStaticText( parent, -1, wxT("") );
wxBoxSizer* range_sizer = new wxBoxSizer( wxHORIZONTAL );
range_sizer->Add( range_label, 0, wxCENTER|wxLEFT, 5 );
range_sizer->Add( range_slider, 1, wxEXPAND|wxLEFT, 5 );
wxBoxSizer* txtbox_szr = new wxBoxSizer( wxHORIZONTAL );
txtbox_szr->Add( textctrl, 1, wxEXPAND, 0 );
wxBoxSizer* mode_szr = NULL;
if ( control_reference->is_input )
{
mode_cbox = new wxChoice( parent, -1 );
mode_cbox->Append( wxT("OR") );
mode_cbox->Append( wxT("AND") );
mode_cbox->Append( wxT("NOT") );
mode_cbox->Select( ((ControllerInterface::InputReference*)control_reference)->mode );
_connect_macro_( mode_cbox, AdjustControlOption, wxEVT_COMMAND_CHOICE_SELECTED );
mode_szr = new wxBoxSizer( wxHORIZONTAL );
mode_szr->Add( new wxStaticText( parent, -1, wxT("Mode") ), 0, wxCENTER|wxLEFT|wxRIGHT, 5 );
mode_szr->Add( mode_cbox, 0, wxLEFT, 5 );
}
Add( range_sizer, 0, wxEXPAND|wxLEFT|wxRIGHT, 5 );
if ( control_reference->is_input )
Add( mode_szr, 0, wxEXPAND|wxLEFT|wxRIGHT, 5 );
Add( txtbox_szr, 0, wxEXPAND|wxTOP|wxLEFT|wxRIGHT, 5 );
Add( button_sizer, 0, wxEXPAND|wxBOTTOM|wxLEFT|wxRIGHT, 5 );
Add( control_lbox, 0, wxEXPAND|wxLEFT|wxRIGHT|wxBOTTOM, 5 );
Add( m_bound_label, 0, wxEXPAND|wxLEFT, 80 );
UpdateGUI();
}
void GamepadPage::LoadProfile( wxCommandEvent& event )
{
// TODO: check for dumb characters maybe
if ( profile_cbox->GetValue().empty() )
return;
m_plugin.controls_crit.Enter();
std::ifstream file;
std::string fname( File::GetUserPath(D_CONFIG_IDX) );
fname += PROFILES_PATH; fname += profile_cbox->GetValue().ToAscii(); fname += ".ini";
if ( false == File::Exists( fname.c_str() ) )
return;
file.open( fname.c_str() );
IniFile inifile;
inifile.Load( file );
controller->LoadConfig( inifile["Profile"] );
file.close();
controller->UpdateReferences( m_plugin.controller_interface );
m_plugin.controls_crit.Leave();
UpdateGUI();
}
void GamepadPage::SaveProfile( wxCommandEvent& event )
{
// TODO: check for dumb characters
if ( profile_cbox->GetValue().empty() )
return;
// don't need lock
IniFile inifile;
controller->SaveConfig( inifile["Profile"] );
std::ofstream file;
std::string fname( File::GetUserPath(D_CONFIG_IDX) );
fname += PROFILES_PATH;
if ( false == File::Exists( fname.c_str() ) )
File::CreateFullPath( fname.c_str() );
fname += profile_cbox->GetValue().ToAscii(); fname += ".ini";
file.open( fname.c_str() );
inifile.Save( file );
file.close();
m_config_dialog->UpdateProfileComboBox();
}
void GamepadPage::DeleteProfile( wxCommandEvent& event )
{
// TODO: check for dumb characters maybe
if ( profile_cbox->GetValue().empty() )
return;
// don't need lock
std::string fname( File::GetUserPath(D_CONFIG_IDX) );
fname += PROFILES_PATH; fname += profile_cbox->GetValue().ToAscii(); fname += ".ini";
if ( File::Exists( fname.c_str() ) )
File::Delete( fname.c_str() );
m_config_dialog->UpdateProfileComboBox();
}
void ConfigDialog::UpdateDeviceComboBox()
{
std::vector< GamepadPage* >::iterator i = m_padpages.begin(),
e = m_padpages.end();
ControllerInterface::DeviceQualifier dq;
for ( ; i != e; ++i )
{
(*i)->device_cbox->Clear();
std::vector<ControllerInterface::Device*>::const_iterator di = m_plugin.controller_interface.Devices().begin(),
de = m_plugin.controller_interface.Devices().end();
for ( ; di!=de; ++di )
{
dq.FromDevice( *di );
(*i)->device_cbox->Append( wxString::FromAscii( dq.ToString().c_str() ) );
}
(*i)->device_cbox->SetValue( wxString::FromAscii( (*i)->controller->default_device.ToString().c_str() ) );
}
}
void GamepadPage::RefreshDevices( wxCommandEvent& event )
{
m_plugin.controls_crit.Enter(); // enter
// refresh devices
m_plugin.controller_interface.DeInit();
m_plugin.controller_interface.Init();
// update all control references
m_config_dialog->UpdateControlReferences();
// update device cbox
m_config_dialog->UpdateDeviceComboBox();
m_plugin.controls_crit.Leave(); // leave
}
ControlGroupBox::ControlGroupBox( ControllerEmu::ControlGroup* const group, wxWindow* const parent )
: wxStaticBoxSizer( wxVERTICAL, parent, wxString::FromAscii( group->name ) )
{
control_group = group;
static_bitmap = NULL;
for ( unsigned int c = 0; c < group->controls.size(); ++c )
{
wxStaticText* label = new wxStaticText( parent, -1, wxString::FromAscii( group->controls[c]->name )/*.append(wxT(" :"))*/ );
ControlButton* control_button = new ControlButton( parent, group->controls[c]->control_ref, 80 );
controls.push_back( control_button );
ControlButton* adv_button = new ControlButton( parent, group->controls[c]->control_ref, 16, "+" );
control_buttons.push_back( control_button );
control_button->Connect( wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( GamepadPage::DetectControl ),
(wxObject*)0, (wxEvtHandler*)parent );
adv_button->Connect( wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( GamepadPage::ConfigControl ),
(wxObject*)0, (wxEvtHandler*)parent );
wxBoxSizer* control_sizer = new wxBoxSizer( wxHORIZONTAL );
control_sizer->AddStretchSpacer( 1 );
control_sizer->Add( label, 0, wxCENTER | wxRIGHT, 5 );
control_sizer->Add( control_button, 0, 0, 0 );
control_sizer->Add( adv_button, 0, 0, 5 );
Add( control_sizer, 0, wxEXPAND|wxLEFT|wxRIGHT, 5 );
}
switch ( group->type )
{
case GROUP_TYPE_STICK :
{
wxBitmap bitmap(64, 64);
wxMemoryDC dc;
dc.SelectObject(bitmap);
dc.Clear();
dc.SelectObject(wxNullBitmap);
static_bitmap = new wxStaticBitmap( parent, -1, bitmap, wxDefaultPosition, wxDefaultSize, wxBITMAP_TYPE_BMP );
PadSettingChoice* deadzone_cbox = new PadSettingChoice( parent, group->settings[0]->value, 1, 50 );
PadSettingChoice* diagonal_cbox = new PadSettingChoice( parent, group->settings[1]->value, 1, 100 );
deadzone_cbox->Connect( wxID_ANY, wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( GamepadPage::AdjustSetting ), (wxObject*)0, (wxEvtHandler*)parent );
diagonal_cbox->Connect( wxID_ANY, wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( GamepadPage::AdjustSetting ), (wxObject*)0, (wxEvtHandler*)parent );
options.push_back( deadzone_cbox );
options.push_back( diagonal_cbox );
wxBoxSizer* szr = new wxBoxSizer( wxVERTICAL );
szr->Add( new wxStaticText( parent, -1, wxString::FromAscii( group->settings[0]->name ) ) );
szr->Add( deadzone_cbox, 0, wxLEFT, 0 );
szr->Add( new wxStaticText( parent, -1, wxString::FromAscii( group->settings[1]->name ) ) );
szr->Add( diagonal_cbox, 0, wxLEFT, 0 );
wxBoxSizer* h_szr = new wxBoxSizer( wxHORIZONTAL );
h_szr->Add( szr, 1, 0, 5 );
h_szr->Add( static_bitmap, 0, wxALL|wxCENTER, 5 );
Add( h_szr, 0, wxEXPAND|wxLEFT|wxCENTER|wxTOP, 5 );
}
break;
case GROUP_TYPE_BUTTONS :
{
wxBitmap bitmap(int(12*group->controls.size()+1), 12);
wxMemoryDC dc;
dc.SelectObject(bitmap);
dc.Clear();
dc.SelectObject(wxNullBitmap);
static_bitmap = new wxStaticBitmap( parent, -1, bitmap, wxDefaultPosition, wxDefaultSize, wxBITMAP_TYPE_BMP );
PadSettingChoice* threshold_cbox = new PadSettingChoice( parent, group->settings[0]->value, 1, 99 );
threshold_cbox->Connect( wxID_ANY, wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( GamepadPage::AdjustSetting ), (wxObject*)0, (wxEvtHandler*)parent );
options.push_back( threshold_cbox );
wxBoxSizer* szr = new wxBoxSizer( wxHORIZONTAL );
szr->Add( new wxStaticText( parent, -1, wxString::FromAscii( group->settings[0]->name ) ), 0, wxCENTER|wxRIGHT, 5 );
szr->Add( threshold_cbox, 0, wxRIGHT, 5 );
Add( szr, 0, wxALL|wxCENTER, 5 );
Add( static_bitmap, 0, wxALL|wxCENTER, 5 );
}
break;
case GROUP_TYPE_MIXED_TRIGGERS :
{
wxBitmap bitmap(64+12+1, int(6*group->controls.size())+1);
wxMemoryDC dc;
dc.SelectObject(bitmap);
dc.Clear();
dc.SelectObject(wxNullBitmap);
static_bitmap = new wxStaticBitmap( parent, -1, bitmap, wxDefaultPosition, wxDefaultSize, wxBITMAP_TYPE_BMP );
PadSettingChoice* threshold_cbox = new PadSettingChoice( parent, group->settings[0]->value, 1, 99 );
threshold_cbox->Connect( wxID_ANY, wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( GamepadPage::AdjustSetting ), (wxObject*)0, (wxEvtHandler*)parent );
options.push_back( threshold_cbox );
wxBoxSizer* szr = new wxBoxSizer( wxHORIZONTAL );
szr->Add( new wxStaticText( parent, -1, wxString::FromAscii( group->settings[0]->name ) ), 0, wxCENTER|wxRIGHT, 5 );
szr->Add( threshold_cbox, 0, wxRIGHT, 5 );
Add( szr, 0, wxALL|wxCENTER, 5 );
Add( static_bitmap, 0, wxALL|wxCENTER, 5 );
}
break;
default :
{
std::vector<ControllerEmu::ControlGroup::Setting*>::const_iterator
i = group->settings.begin(),
e = group->settings.end();
for ( ; i!=e; ++i )
{
PadSettingCheckBox* setting_cbox = new PadSettingCheckBox( parent, (*i)->value, (*i)->name );
setting_cbox->Connect( wxID_ANY, wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( GamepadPage::AdjustSetting ), (wxObject*)0, (wxEvtHandler*)parent );
options.push_back( setting_cbox );
Add( setting_cbox, 0, wxALL|wxCENTER, 5 );
}
}
break;
}
//AddStretchSpacer( 0 );
}
GamepadPage::GamepadPage( wxWindow* parent, Plugin& plugin, const unsigned int pad_num, ConfigDialog* const config_dialog )
: wxNotebookPage( parent, -1 , wxDefaultPosition, wxDefaultSize )
,controller(plugin.controllers[pad_num])
,m_plugin(plugin)
,m_config_dialog(config_dialog)
{
wxBoxSizer* control_group_sizer = new wxBoxSizer( wxHORIZONTAL );
wxBoxSizer* stacked_groups = NULL;
for ( unsigned int i = 0; i < m_plugin.controllers[pad_num]->groups.size(); ++i )
{
ControlGroupBox* control_group = new ControlGroupBox( m_plugin.controllers[pad_num]->groups[i], this );
if ( control_group->control_buttons.size() > 2 )
{
if ( stacked_groups )
control_group_sizer->Add( stacked_groups, 0, /*wxEXPAND|*/wxBOTTOM|wxRIGHT, 5 );
stacked_groups = new wxBoxSizer( wxVERTICAL );
stacked_groups->Add( control_group, 0, wxEXPAND );
}
else
stacked_groups->Add( control_group, 0, wxEXPAND );
control_groups.push_back( control_group );
}
if ( stacked_groups )
control_group_sizer->Add( stacked_groups, 0, /*wxEXPAND|*/wxBOTTOM|wxRIGHT, 5 );
wxStaticBoxSizer* profile_sbox = new wxStaticBoxSizer( wxHORIZONTAL, this, wxT("Profile") );
// device chooser
wxStaticBoxSizer* device_sbox = new wxStaticBoxSizer( wxHORIZONTAL, this, wxT("Device") );
device_cbox = new wxComboBox( this, -1, wxT(""), wxDefaultPosition, wxSize(128,-1), 0, 0, wxTE_PROCESS_ENTER );
wxButton* refresh_button = new wxButton( this, -1, wxT("Refresh"), wxDefaultPosition, wxSize(48,-1) );
#define _connect_macro3_( b, f, c ) (b)->Connect( wxID_ANY, c, wxCommandEventHandler( GamepadPage::f ), (wxObject*)0, (wxEvtHandler*)this );
_connect_macro3_( device_cbox, SetDevice, wxEVT_COMMAND_COMBOBOX_SELECTED );
_connect_macro3_( device_cbox, SetDevice, wxEVT_COMMAND_TEXT_ENTER );
_connect_macro3_( refresh_button, RefreshDevices, wxEVT_COMMAND_BUTTON_CLICKED );
device_sbox->Add( device_cbox, 1, wxLEFT|wxRIGHT, 5 );
device_sbox->Add( refresh_button, 0, wxRIGHT|wxBOTTOM, 5 );
wxStaticBoxSizer* clear_sbox = new wxStaticBoxSizer( wxHORIZONTAL, this, wxT("Clear") );
wxButton* all_button = new wxButton( this, -1, wxT("All"), wxDefaultPosition, wxSize(48,-1) );
clear_sbox->Add( all_button, 1, wxLEFT|wxRIGHT, 5 );
all_button->Connect( wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( GamepadPage::ClearAll ),
(wxObject*)0, (wxEvtHandler*)this );
profile_cbox = new wxComboBox( this, -1, wxT(""), wxDefaultPosition, wxSize(128,-1) );
wxButton* const pload_btn = new wxButton( this, -1, wxT("Load"), wxDefaultPosition, wxSize(48,-1) );
wxButton* const psave_btn = new wxButton( this, -1, wxT("Save"), wxDefaultPosition, wxSize(48,-1) );
wxButton* const pdelete_btn = new wxButton( this, -1, wxT("Delete"), wxDefaultPosition, wxSize(48,-1) );
pload_btn->Connect( wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( GamepadPage::LoadProfile ),
(wxObject*)0, (wxEvtHandler*)this );
psave_btn->Connect( wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( GamepadPage::SaveProfile ),
(wxObject*)0, (wxEvtHandler*)this );
pdelete_btn->Connect( wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( GamepadPage::DeleteProfile ),
(wxObject*)0, (wxEvtHandler*)this );
profile_sbox->Add( profile_cbox, 1, wxLEFT, 5 );
profile_sbox->Add( pload_btn, 0, wxLEFT, 5 );
profile_sbox->Add( psave_btn, 0, 0, 5 );
profile_sbox->Add( pdelete_btn, 0, wxRIGHT|wxBOTTOM, 5 );
wxBoxSizer* dio = new wxBoxSizer( wxHORIZONTAL );
dio->Add( device_sbox, 1, wxEXPAND|wxRIGHT, 5 );
dio->Add( clear_sbox, 0, wxEXPAND|wxRIGHT, 5 );
dio->Add( profile_sbox, 1, wxEXPAND|wxRIGHT, 5 );
wxBoxSizer* mapping = new wxBoxSizer( wxVERTICAL );
mapping->Add( dio, 1, wxEXPAND|wxLEFT|wxTOP|wxBOTTOM, 5 );
mapping->Add( control_group_sizer, 0, wxLEFT|wxEXPAND, 5 );
UpdateGUI();
SetSizerAndFit( mapping );
Layout();
};
ConfigDialog::~ConfigDialog()
{
m_update_timer->Stop();
}
ConfigDialog::ConfigDialog( wxWindow* const parent, Plugin& plugin, const std::string& name, const bool _is_game_running )
: wxDialog( parent, wxID_ANY, wxString::FromAscii(name.c_str()), wxPoint(128,-1), wxDefaultSize )
, is_game_running(_is_game_running)
, m_plugin(plugin)
{
m_pad_notebook = new wxNotebook( this, -1, wxDefaultPosition, wxDefaultSize, wxNB_DEFAULT );
for ( unsigned int i = 0; i < plugin.controllers.size(); ++i )
{
GamepadPage* gp = new GamepadPage( m_pad_notebook, plugin, i, this );
m_padpages.push_back( gp );
m_pad_notebook->AddPage( gp, wxString::FromAscii((plugin.controllers[i]->GetName().c_str())) );
}
UpdateDeviceComboBox();
UpdateProfileComboBox();
wxButton* close_button = new wxButton( this, -1, wxT("Save"));
close_button->Connect( wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( ConfigDialog::ClickSave ), (wxObject*)0, (wxEvtHandler*)this );
wxBoxSizer* btns = new wxBoxSizer( wxHORIZONTAL );
//btns->Add( new wxStaticText( this, -1, wxString::FromAscii(ver.c_str())), 0, wxLEFT|wxTOP, 5 );
btns->AddStretchSpacer();
btns->Add( close_button, 0, 0, 0 );
wxBoxSizer* szr = new wxBoxSizer( wxVERTICAL );
szr->Add( m_pad_notebook, 0, wxEXPAND|wxTOP|wxLEFT|wxRIGHT, 5 );
szr->Add( btns, 0, wxEXPAND|wxALL, 5 );
SetSizerAndFit( szr );
// not needed here it seems, but it cant hurt
//Layout();
Center();
// live preview update timer
m_update_timer = new wxTimer( this, -1 );
Connect( wxID_ANY, wxEVT_TIMER, wxTimerEventHandler( ConfigDialog::UpdateBitmaps ), (wxObject*)0, this );
m_update_timer->Start( PREVIEW_UPDATE_TIME, wxTIMER_CONTINUOUS);
}
@@ -0,0 +1,187 @@
#ifndef _CONFIGBOX_H_
#define _CONFIGBOX_H_
#define SLIDER_TICK_COUNT 100
#define DETECT_WAIT_TIME 1500
#define PREVIEW_UPDATE_TIME 25
// might have to change this setup for wiimote
#define PROFILES_PATH "Profiles/GCPad/"
#include <wx/wx.h>
#include <wx/listbox.h>
#include <wx/textctrl.h>
#include <wx/button.h>
#include <wx/stattext.h>
#include <wx/combobox.h>
#include <wx/checkbox.h>
#include <wx/notebook.h>
#include <wx/panel.h>
#include <sstream>
#include <vector>
#include "ControllerInterface/ControllerInterface.h"
#include "Config.h"
#include "FileSearch.h"
class PadSetting
{
protected:
PadSetting( ControlState& _value ) : value(_value) {}
public:
virtual void UpdateGUI() = 0;
virtual void UpdateValue() = 0;
ControlState& value;
};
class PadSettingChoice : public PadSetting, public wxChoice
{
public:
PadSettingChoice( wxWindow* const parent, ControlState& _value, int min, int max );
void UpdateGUI();
void UpdateValue();
};
class PadSettingCheckBox : public PadSetting, public wxCheckBox
{
public:
PadSettingCheckBox( wxWindow* const parent, ControlState& _value, const char* const label );
void UpdateGUI();
void UpdateValue();
};
class ControlChooser : public wxStaticBoxSizer
{
public:
ControlChooser( wxWindow* const parent, ControllerInterface::ControlReference* const ref, wxWindow* const eventsink );
void UpdateGUI();
ControllerInterface::ControlReference* control_reference;
wxTextCtrl* textctrl;
wxListBox* control_lbox;
wxChoice* mode_cbox;
wxSlider* range_slider;
private:
wxStaticText* m_bound_label;
};
class ControlList : public wxDialog
{
public:
ControlList( wxWindow* const parent, ControllerInterface::ControlReference* const ref, ControlChooser* const chooser );
private:
ControlChooser* const m_control_chooser;
};
class ControlDialog : public wxDialog
{
public:
ControlDialog( wxWindow* const parent, ControllerInterface::ControlReference* const ref, const std::vector<ControllerInterface::Device*>& devs );
void SelectControl( wxCommandEvent& event );
ControllerInterface::ControlReference* const control_reference;
wxComboBox* device_cbox;
ControlChooser* control_chooser;
};
class ControlButton : public wxButton
{
public:
ControlButton( wxWindow* const parent, ControllerInterface::ControlReference* const _ref, const unsigned int width, const std::string& label = "" );
ControllerInterface::ControlReference* const control_reference;
};
class ControlGroupBox : public wxStaticBoxSizer
{
public:
ControlGroupBox( ControllerEmu::ControlGroup* const group, wxWindow* const parent );
ControllerEmu::ControlGroup* control_group;
wxStaticBitmap* static_bitmap;
std::vector< PadSetting* > options;
std::vector< wxButton* > controls;
std::vector<ControlButton*> control_buttons;
};
class ConfigDialog;
class GamepadPage : public wxNotebookPage
{
friend class ConfigDialog;
public:
GamepadPage( wxWindow* parent, Plugin& plugin, const unsigned int pad_num, ConfigDialog* const config_dialog );
void UpdateGUI();
void RefreshDevices( wxCommandEvent& event );
void LoadProfile( wxCommandEvent& event );
void SaveProfile( wxCommandEvent& event );
void DeleteProfile( wxCommandEvent& event );
void ConfigControl( wxCommandEvent& event );
void ConfigDetectControl( wxCommandEvent& event );
void DetectControl( wxCommandEvent& event );
void ClearControl( wxCommandEvent& event );
void SetDevice( wxCommandEvent& event );
void SetControl( wxCommandEvent& event );
void ClearAll( wxCommandEvent& event );
void AdjustControlOption( wxCommandEvent& event );
void AdjustSetting( wxCommandEvent& event );
wxComboBox* profile_cbox;
wxComboBox* device_cbox;
std::vector<ControlGroupBox*> control_groups;
protected:
ControllerEmu* const controller;
private:
ControlDialog* m_control_dialog;
Plugin& m_plugin;
ConfigDialog* const m_config_dialog;
};
class ConfigDialog : public wxDialog
{
public:
ConfigDialog( wxWindow* const parent, Plugin& plugin, const std::string& name, const bool _is_game_running );
~ConfigDialog();
void ClickSave( wxCommandEvent& event );
void UpdateDeviceComboBox();
void UpdateProfileComboBox();
void UpdateControlReferences();
void UpdateBitmaps(wxTimerEvent&);
const bool is_game_running;
private:
wxNotebook* m_pad_notebook;
std::vector<GamepadPage*> m_padpages;
Plugin& m_plugin;
wxTimer* m_update_timer;
};
#endif
@@ -0,0 +1,187 @@
#include "ConfigDiag.h"
void ConfigDialog::UpdateBitmaps(wxTimerEvent& WXUNUSED(event))
{
GamepadPage* const current_page = (GamepadPage*)m_pad_notebook->GetPage( m_pad_notebook->GetSelection() );
std::vector< ControlGroupBox* >::iterator g = current_page->control_groups.begin(),
ge = current_page->control_groups.end();
for ( ; g != ge; ++g )
{
if ( (*g)->static_bitmap )
{
// don't want game thread updating input when we are using it here
if ( false == m_plugin.interface_crit.TryEnter() )
return;
//if ( false == is_game_running )
// just always update
m_plugin.controller_interface.UpdateInput();
switch ( (*g)->control_group->type )
{
case GROUP_TYPE_STICK :
{
float x, y;
float xx, yy;
((ControllerEmu::AnalogStick*)(*g)->control_group)->GetState( &x, &y, 32.0, 32-1.5 );
xx = ((ControllerEmu::AnalogStick*)(*g)->control_group)->controls[3]->control_ref->State();
xx -= ((ControllerEmu::AnalogStick*)(*g)->control_group)->controls[2]->control_ref->State();
yy = ((ControllerEmu::AnalogStick*)(*g)->control_group)->controls[1]->control_ref->State();
yy -= ((ControllerEmu::AnalogStick*)(*g)->control_group)->controls[0]->control_ref->State();
xx *= 32 - 1; xx += 32;
yy *= 32 - 1; yy += 32;
// setup
wxBitmap bitmap(64, 64);
wxMemoryDC dc;
dc.SelectObject(bitmap);
dc.Clear();
// draw the shit
// circle for visual aid for diagonal adjustment
dc.SetPen(*wxLIGHT_GREY_PEN);
dc.SetBrush(*wxTRANSPARENT_BRUSH);
dc.DrawCircle( 32, 32, 32);
// deadzone circle
dc.SetBrush(*wxLIGHT_GREY_BRUSH);
dc.DrawCircle( 32, 32, ((ControllerEmu::AnalogStick*)(*g)->control_group)->settings[0]->value * 32 );
// raw dot
dc.SetPen(*wxGREY_PEN);
dc.SetBrush(*wxGREY_BRUSH);
// i like the dot better than the cross i think
dc.DrawRectangle( xx - 2, yy - 2, 4, 4 );
//dc.DrawRectangle( xx-1, 64-yy-4, 2, 8 );
//dc.DrawRectangle( xx-4, 64-yy-1, 8, 2 );
// adjusted dot
if ( x!=32 || y!=32 )
{
dc.SetPen(*wxRED_PEN);
dc.SetBrush(*wxRED_BRUSH);
dc.DrawRectangle( x-2, 64-y-2, 4, 4 );
// i like the dot better than the cross i think
//dc.DrawRectangle( x-1, 64-y-4, 2, 8 );
//dc.DrawRectangle( x-4, 64-y-1, 8, 2 );
}
// box outline
// Windows XP color
dc.SetPen(wxPen(_T("#7f9db9")));
dc.SetBrush(*wxTRANSPARENT_BRUSH);
dc.DrawRectangle(0, 0, 64, 64);
// done drawing
dc.SelectObject(wxNullBitmap);
// set the shit
(*g)->static_bitmap->SetBitmap( bitmap );
}
break;
case GROUP_TYPE_BUTTONS :
{
const unsigned int button_count = ((unsigned int)(*g)->control_group->controls.size());
// setup
wxBitmap bitmap(12*button_count+1, 12);
wxMemoryDC dc;
dc.SelectObject(bitmap);
dc.Clear();
// draw the shit
dc.SetPen(*wxGREY_PEN);
unsigned int * const bitmasks = new unsigned int[ button_count ];
for ( unsigned int n = 0; n<button_count; ++n )
bitmasks[n] = ( 1 << n );
unsigned int buttons = 0;
((ControllerEmu::Buttons*)(*g)->control_group)->GetState( &buttons, bitmasks );
for ( unsigned int n = 0; n<button_count; ++n )
{
// TODO: threshold stuff, actually redo this crap with the GetState func
if ( buttons & bitmasks[n] )
dc.SetBrush( *wxRED_BRUSH );
else
{
unsigned char amt = 255 - (*g)->control_group->controls[n]->control_ref->State() * 128;
dc.SetBrush( wxBrush( wxColor( amt, amt, amt ) ) );
}
dc.DrawRectangle(n*12, 0, 14, 12);
}
delete bitmasks;
// box outline
// Windows XP color
dc.SetPen(wxPen(_T("#7f9db9")));
dc.SetBrush(*wxTRANSPARENT_BRUSH);
dc.DrawRectangle(0, 0, bitmap.GetWidth(), bitmap.GetHeight());
// done drawing
dc.SelectObject(wxNullBitmap);
// set the shit
(*g)->static_bitmap->SetBitmap( bitmap );
}
break;
case GROUP_TYPE_MIXED_TRIGGERS :
{
const unsigned int trigger_count = ((unsigned int)((*g)->control_group->controls.size() / 2));
// setup
wxBitmap bitmap( 64+12+1, 12*trigger_count+1);
wxMemoryDC dc;
dc.SelectObject(bitmap);
dc.Clear();
// draw the shit
dc.SetPen(*wxGREY_PEN);
ControlState thresh = (*g)->control_group->settings[0]->value;
for ( unsigned int n = 0; n < trigger_count; ++n )
{
dc.SetBrush(*wxRED_BRUSH);
ControlState trig_d = (*g)->control_group->controls[n]->control_ref->State();
ControlState trig_a = trig_d > thresh ? 1
: (*g)->control_group->controls[n+trigger_count]->control_ref->State();
dc.DrawRectangle(0, n*12, 64+20, 14);
if ( trig_d <= thresh )
dc.SetBrush(*wxWHITE_BRUSH);
dc.DrawRectangle(trig_a*64, n*12, 64+20, 14);
dc.DrawRectangle(64, n*12, 32, 14);
}
dc.SetBrush(*wxTRANSPARENT_BRUSH);
dc.DrawRectangle(thresh*64, 0, 128, trigger_count*14);
// box outline
// Windows XP color
dc.SetPen(wxPen(_T("#7f9db9")));
dc.DrawRectangle(0, 0, bitmap.GetWidth(), bitmap.GetHeight());
// done drawing
dc.SelectObject(wxNullBitmap);
// set the shit
(*g)->static_bitmap->SetBitmap( bitmap );
}
break;
default :
break;
}
m_plugin.interface_crit.Leave();
}
}
}
@@ -0,0 +1,138 @@
#include "ControllerEmu.h"
#include "ControllerEmu/GCPad/GCPad.h"
const char modifier[] = "Modifier";
// TODO: make this use iterators
ControllerEmu::~ControllerEmu()
{
for ( unsigned int g = 0; g<groups.size(); ++g )
delete groups[g];
}
// TODO: make this use iterators
ControllerEmu::ControlGroup::~ControlGroup()
{
for ( unsigned int i = 0; i < controls.size(); ++i )
delete controls[i];
for ( unsigned int i = 0; i < settings.size(); ++i )
delete settings[i];
}
// TODO: make this use iterators
void ControllerEmu::UpdateReferences( ControllerInterface& devi )
{
for ( unsigned int g = 0; g<groups.size(); ++g )
for ( unsigned int i = 0; i < groups[g]->controls.size(); ++i )
devi.UpdateReference( groups[g]->controls[i]->control_ref );
}
void ControllerEmu::UpdateDefaultDevice()
{
std::vector<ControlGroup*>::const_iterator i = groups.begin(),
e = groups.end();
for ( ; i!=e; ++i )
{
std::vector<ControlGroup::Control*>::const_iterator ci = (*i)->controls.begin(),
ce = (*i)->controls.end();
for ( ; ci!=ce; ++ci )
(*ci)->control_ref->device_qualifier = default_device;
}
}
void ControllerEmu::LoadConfig( IniFile::Section& sec )
{
const std::string default_dev = sec[ "Device" ];
default_device.FromString( default_dev );
std::vector<ControlGroup*>::const_iterator i = groups.begin(),
e = groups.end();
for ( ; i!=e; ++i )
{
std::string group( (*i)->name ); group += "/";
// settings
std::vector<ControlGroup::Setting*>::const_iterator si = (*i)->settings.begin(),
se = (*i)->settings.end();
for ( ; si!=se; ++si )
(*si)->value = sec.Get(group+(*si)->name, (*si)->default_value*100) / 100;
// controls
std::vector<ControlGroup::Control*>::const_iterator ci = (*i)->controls.begin(),
ce = (*i)->controls.end();
for ( ; ci!=ce; ++ci )
{
// control and dev qualifier
(*ci)->control_ref->control_qualifier.name = sec[group + (*ci)->name];
(*ci)->control_ref->device_qualifier.FromString( sec.Get( group+(*ci)->name+"/Device", default_dev ) );
// range
(*ci)->control_ref->range = sec.Get( group+(*ci)->name+"/Range", 100.0f ) / 100;
// input mode
if ( (*ci)->control_ref->is_input )
((ControllerInterface::InputReference*)((*ci)->control_ref))->mode
= sec.Get( group+(*ci)->name+"/Mode", 0 );
}
}
}
void ControllerEmu::SaveConfig( IniFile::Section& sec )
{
const std::string default_dev = default_device.ToString();
sec[ " Device" ] = default_dev;
std::vector<ControlGroup*>::const_iterator i = groups.begin(),
e = groups.end();
for ( ; i!=e; ++i )
{
std::string group( (*i)->name ); group += "/";
// settings
std::vector<ControlGroup::Setting*>::const_iterator si = (*i)->settings.begin(),
se = (*i)->settings.end();
for ( ; si!=se; ++si )
sec.Set( group+(*si)->name, (*si)->value*100, (*si)->default_value*100 );
// controls
std::vector<ControlGroup::Control*>::const_iterator ci = (*i)->controls.begin(),
ce = (*i)->controls.end();
for ( ; ci!=ce; ++ci )
{
// control and dev qualifier
sec[group + (*ci)->name] = (*ci)->control_ref->control_qualifier.name;
sec.Set( group+(*ci)->name+"/Device", (*ci)->control_ref->device_qualifier.ToString(), default_dev );
// range
sec.Set( group+(*ci)->name+"/Range", (*ci)->control_ref->range*100, 100 );
// input mode
if ( (*ci)->control_ref->is_input )
sec.Set( group+(*ci)->name+"/Mode",
((ControllerInterface::InputReference*)((*ci)->control_ref))->mode, (unsigned int)0 );
}
}
}
ControllerEmu::AnalogStick::AnalogStick( const char* const _name ) : ControlGroup( _name, GROUP_TYPE_STICK )
{
for ( unsigned int i = 0; i < 4; ++i )
controls.push_back( new Input( named_directions[i] ) );
controls.push_back( new Input( modifier ) );
settings.push_back( new Setting("Dead Zone", 0 ) );
settings.push_back( new Setting("Square Stick", 0 ) );
}
ControllerEmu::Buttons::Buttons( const char* const _name ) : ControlGroup( _name, GROUP_TYPE_BUTTONS )
{
settings.push_back( new Setting("Threshold", 0.5f ) );
}
ControllerEmu::MixedTriggers::MixedTriggers( const char* const _name ) : ControlGroup( _name, GROUP_TYPE_MIXED_TRIGGERS )
{
settings.push_back( new Setting("Threshold", 0.9f ) );
}
@@ -0,0 +1,227 @@
#ifndef _CONTROLLEREMU_H_
#define _CONTROLLEREMU_H_
// windows crap
#define NOMINMAX
#include "pluginspecs_pad.h"
#include "pluginspecs_wiimote.h"
//#include <CommonTypes.h>
#include <math.h>
#include "ControllerInterface/ControllerInterface.h"
#include "IniFile.h"
#include <vector>
#include <string>
#include <algorithm>
#define sign(x) ((x)?(x)<0?-1:1:0)
enum
{
GROUP_TYPE_OTHER
,GROUP_TYPE_STICK
,GROUP_TYPE_MIXED_TRIGGERS
,GROUP_TYPE_BUTTONS
};
const char * const named_directions[] =
{
"Up",
"Down",
"Left",
"Right"
};
class ControllerEmu
{
public:
class ControlGroup
{
public:
class Control
{
protected:
Control( ControllerInterface::ControlReference* const _ref, const char * const _name )
: control_ref(_ref), name(_name){}
public:
//virtual std::string GetName() const = 0;
ControllerInterface::ControlReference* const control_ref;
const char * const name;
};
class Input : public Control
{
public:
Input( const char * const _name )
: Control( new ControllerInterface::InputReference, _name ) {}
};
class Output : public Control
{
public:
Output( const char * const _name )
: Control( new ControllerInterface::OutputReference, _name ) {}
};
class Setting
{
public:
Setting(const char* const _name, const float def_value ) : name(_name), value(def_value), default_value(def_value) {}
const char* const name;
ControlState value;
const ControlState default_value;
};
ControlGroup( const char* const _name, const unsigned int _type = GROUP_TYPE_OTHER ) : name(_name), type(_type) {}
virtual ~ControlGroup();
//ControlGroup( const ControlGroup& ctrl );
//const unsigned int type;
const char* const name;
const unsigned int type;
std::vector< Control* > controls;
std::vector< Setting* > settings;
};
class AnalogStick : public ControlGroup
{
public:
template <typename C>
void GetState( C* const x, C* const y, const unsigned int base, const unsigned int range )
{
// this is all a mess
ControlState yy = controls[0]->control_ref->State() - controls[1]->control_ref->State();
ControlState xx = controls[3]->control_ref->State() - controls[2]->control_ref->State();
ControlState deadzone = settings[0]->value;
ControlState square = settings[1]->value;
ControlState m = controls[4]->control_ref->State();
// modifier code
if ( m )
{
yy = (abs(yy)>deadzone) * sign(yy) * m;
xx = (abs(xx)>deadzone) * sign(xx) * m;
}
// deadzone / square stick code
if ( deadzone || square )
{
// this section might be all wrong, but its working good enough, i think
ControlState ang = atan2( yy, xx );
ControlState ang_sin = sin(ang);
ControlState ang_cos = cos(ang);
// the amt a full square stick would have at current angle
ControlState square_full = std::min( 1/abs(ang_sin), 1/abs(ang_cos) );
// the amt a full stick would have that was ( user setting squareness) at current angle
// i think this is more like a pointed circle rather than a rounded square like it should be
ControlState stick_full = ( 1 + ( square_full - 1 ) * square );
ControlState dist = sqrt(xx*xx + yy*yy);
// dead zone code
dist = std::max( 0.0f, dist - deadzone * stick_full );
dist /= ( 1 - deadzone );
// square stick code
ControlState amt = ( dist ) / stick_full;
dist -= ((square_full - 1) * amt * square);
yy = std::max( -1.0f, std::min( 1.0f, ang_sin * dist ) );
xx = std::max( -1.0f, std::min( 1.0f, ang_cos * dist ) );
}
*y = C( yy * range + base );
*x = C( xx * range + base );
}
AnalogStick( const char* const _name );
};
class Buttons : public ControlGroup
{
public:
Buttons( const char* const _name );
template <typename C>
void GetState( C* const buttons, const C* bitmasks )
{
std::vector<Control*>::iterator i = controls.begin(),
e = controls.end();
for ( ; i!=e; ++i, ++bitmasks )
if ( (*i)->control_ref->State() > settings[0]->value ) // threshold
*buttons |= *bitmasks;
}
};
class MixedTriggers : public ControlGroup
{
public:
template <typename C, typename S>
void GetState( C* const digital, const C* bitmasks, S* analog, const unsigned int range )
{
const unsigned int trig_count = ((unsigned int) (controls.size() / 2));
for ( unsigned int i=0; i<trig_count; ++i,++bitmasks,++analog )
{
if ( controls[i]->control_ref->State() > settings[0]->value ) //threshold
{
*analog = range;
*digital |= *bitmasks;
}
else
*analog = S(controls[i+trig_count]->control_ref->State() * range);
}
}
MixedTriggers( const char* const _name );
};
virtual ~ControllerEmu();
virtual std::string GetName() const = 0;
void LoadConfig( IniFile::Section& sec );
void SaveConfig( IniFile::Section& sec );
void UpdateDefaultDevice();
void UpdateReferences( ControllerInterface& devi );
std::vector< ControlGroup* > groups;
ControlGroup* options;
ControllerInterface::DeviceQualifier default_device;
};
#endif
@@ -0,0 +1,101 @@
#include "GCPad.h"
// this is all temporary, but sticking with the padspecs ...for now
const u16 button_bitmasks[] =
{
PAD_BUTTON_A,
PAD_BUTTON_B,
PAD_BUTTON_X,
PAD_BUTTON_Y,
PAD_TRIGGER_Z,
PAD_BUTTON_START
};
const u16 trigger_bitmasks[] =
{
PAD_TRIGGER_L,
PAD_TRIGGER_R,
};
const u16 dpad_bitmasks[] =
{
PAD_BUTTON_UP, PAD_BUTTON_DOWN, PAD_BUTTON_LEFT, PAD_BUTTON_RIGHT
};
const char* const named_buttons[] =
{
"A",
"B",
"X",
"Y",
"Z",
"Start",
};
const char* const named_triggers[] =
{
"L", "R", "L-Analog", "R-Analog"
};
GCPad::GCPad( const unsigned int index ) : m_index(index)
{
// buttons
groups.push_back( m_buttons = new Buttons( "Buttons" ) );
for ( unsigned int i=0; i < sizeof(named_buttons)/sizeof(*named_buttons); ++i )
m_buttons->controls.push_back( new ControlGroup::Input( named_buttons[i] ) );
// sticks
groups.push_back( m_main_stick = new AnalogStick( "Main Stick" ) );
groups.push_back( m_c_stick = new AnalogStick( "C-Stick" ) );
// triggers
groups.push_back( m_triggers = new MixedTriggers( "Triggers" ) );
for ( unsigned int i=0; i < sizeof(named_triggers)/sizeof(*named_triggers); ++i )
m_triggers->controls.push_back( new ControlGroup::Input( named_triggers[i] ) );
// rumble
groups.push_back( m_rumble = new ControlGroup( "Rumble" ) );
m_rumble->controls.push_back( new ControlGroup::Output( "Motor" ) );
// dpad
groups.push_back( m_dpad = new Buttons( "D-Pad" ) );
for ( unsigned int i=0; i < 4; ++i )
m_dpad->controls.push_back( new ControlGroup::Input( named_directions[i] ) );
// options
groups.push_back( options = new ControlGroup( "Options" ) );
options->settings.push_back( new ControlGroup::Setting( "Background Input", false ) );
}
std::string GCPad::GetName() const
{
return std::string("GCPad") + char('1'+m_index);
}
void GCPad::GetInput( SPADStatus* const pad )
{
std::vector< ControlGroup::Control* >::iterator i,e;
// buttons
m_buttons->GetState( &pad->button, button_bitmasks );
// TODO: set analog A/B to full or w/e
// dpad
m_dpad->GetState( &pad->button, dpad_bitmasks );
// sticks
m_main_stick->GetState( &pad->stickX, &pad->stickY, 0x80, 127 );
m_c_stick->GetState( &pad->substickX, &pad->substickY, 0x80, 127 );
// triggers
m_triggers->GetState( &pad->button, trigger_bitmasks, &pad->triggerLeft, 0xFF );
}
void GCPad::SetOutput( const bool on )
{
m_rumble->controls[0]->control_ref->State( on );
}
@@ -0,0 +1,31 @@
#ifndef _CONEMU_GCPAD_H_
#define _CONEMU_GCPAD_H_
#include "../../ControllerEmu.h"
class GCPad : public ControllerEmu
{
public:
GCPad( const unsigned int index );
void GetInput( SPADStatus* const pad );
void SetOutput( const bool on );
std::string GetName() const;
private:
Buttons* m_buttons;
AnalogStick* m_main_stick;
AnalogStick* m_c_stick;
Buttons* m_dpad;
MixedTriggers* m_triggers;
ControlGroup* m_rumble;
const unsigned int m_index;
};
#endif
@@ -0,0 +1,551 @@
#include "ControllerInterface.h"
namespace ciface {
}
#ifdef CIFACE_USE_XINPUT
#include "XInput/XInput.h"
#endif
#ifdef CIFACE_USE_DIRECTINPUT
#include "DirectInput/DirectInput.h"
#endif
#ifdef CIFACE_USE_XLIB
#include "Xlib/Xlib.h"
#endif
#ifdef CIFACE_USE_OSX
#include "OSX/OSX.h"
#endif
#ifdef CIFACE_USE_SDL
#include "SDL/SDL.h"
#endif
#include "Thread.h"
//#define MAX_DOUBLE_TAP_TIME 400
//#define MAX_HOLD_DOWN_TIME 400
#define INPUT_DETECT_THRESHOLD 0.85
//
// Init
//
// detect devices and inputs outputs / will make refresh function later
//
void ControllerInterface::Init()
{
if ( m_is_init )
return;
#ifdef CIFACE_USE_XINPUT
ciface::XInput::Init( m_devices );
#endif
#ifdef CIFACE_USE_DIRECTINPUT
ciface::DirectInput::Init( m_devices/*, (HWND)m_hwnd*/ );
#endif
#ifdef CIFACE_USE_XLIB
ciface::Xlib::Init( m_devices, m_hwnd );
#endif
#ifdef CIFACE_USE_OSX
ciface::OSX::Init( m_devices, m_hwnd );
#endif
#ifdef CIFACE_USE_SDL
ciface::SDL::Init( m_devices );
#endif
m_is_init = true;
}
//
// DeInit
//
// remove all devices/ call library cleanup functions
//
void ControllerInterface::DeInit()
{
if ( false == m_is_init )
return;
std::vector<Device*>::const_iterator d = m_devices.begin(),
Devices_end = m_devices.end();
for ( ;d != Devices_end; ++d )
{
std::vector<Device::Output*>::const_iterator o = (*d)->Outputs().begin(),
e = (*d)->Outputs().end();
// set outputs to ZERO before destroying device
for ( ;o!=e; ++o)
(*d)->SetOutputState( *o, 0 );
// update output
(*d)->UpdateOutput();
//delete device
delete *d;
}
m_devices.clear();
#ifdef CIFACE_USE_XINPUT
// nothing needed
#endif
#ifdef CIFACE_USE_DIRECTINPUT
// nothing needed
#endif
#ifdef CIFACE_USE_XLIB
// nothing needed
#endif
#ifdef CIFACE_USE_OSX
// nothing needed
#endif
#ifdef CIFACE_USE_SDL
// there seems to be some sort of memory leak with SDL, quit isn't freeing everything up
SDL_Quit();
#endif
m_is_init = false;
}
//
// SetHwnd
//
// sets the hwnd used for some crap when initializing, use before calling Init
//
void ControllerInterface::SetHwnd( void* const hwnd )
{
m_hwnd = hwnd;
}
//
// UpdateInput
//
// update input for all devices, return true if all devices returned successful
//
bool ControllerInterface::UpdateInput()
{
size_t ok_count = 0;
std::vector<Device*>::const_iterator d = m_devices.begin(),
e = m_devices.end();
for ( ;d != e; ++d )
{
if ( (*d)->UpdateInput() )
++ok_count;
else
(*d)->ClearInputState();
}
return ( m_devices.size() == ok_count );
}
//
// UpdateOutput
//
// update output for all devices, return true if all devices returned successful
//
bool ControllerInterface::UpdateOutput()
{
size_t ok_count = 0;
std::vector<Device*>::const_iterator d = m_devices.begin(),
e = m_devices.end();
for ( ;d != e; ++d )
(*d)->UpdateOutput();
return ( m_devices.size() == ok_count );
}
//
// Devices
//
// i dont really like this but,
// return : constant copy of the devices vector
//
const std::vector<ControllerInterface::Device*>& ControllerInterface::Devices()
{
return m_devices;
}
//
// Device :: ~Device
//
// dtor, delete all inputs/outputs on device destruction
//
ControllerInterface::Device::~Device()
{
{
// delete inputs
std::vector<Device::Input*>::iterator i = inputs.begin(),
e = inputs.end();
for ( ;i!=e; ++i)
delete *i;
}
{
// delete outputs
std::vector<Device::Output*>::iterator o = outputs.begin(),
e = outputs.end();
for ( ;o!=e; ++o)
delete *o;
}
}
//
// Device :: ClearInputState
//
// device classes should override this func
// ControllerInterface will call this when the device returns failure durring UpdateInput
// used to try to set all buttons and axes to their default state when user unplugs a gamepad durring play
// buttons/axes that were held down at the time of unplugging should be seen as not pressed after unplugging
//
void ControllerInterface::Device::ClearInputState()
{
// this is going to be called for every UpdateInput call that fails
// kinda slow but, w/e, should only happen when user unplugs a device while playing
}
//
// Device :: Inputs
//
// get a const version of the device's input vector
//
const std::vector<ControllerInterface::Device::Input*>& ControllerInterface::Device::Inputs()
{
return inputs;
}
//
// Device :: Outputs
//
// get a const version of the device's outputs vector
//
const std::vector<ControllerInterface::Device::Output*>& ControllerInterface::Device::Outputs()
{
return outputs;
}
//
// HasInit
//
// check if interface is inited
//
bool ControllerInterface::IsInit()
{
return m_is_init;
}
//
// InputReference :: State
//
// get the state of an input reference
// override function for ControlReference::State ...
//
ControlState ControllerInterface::InputReference::State( const ControlState ignore )
{
if ( NULL == device )
return 0;
ControlState state = 0;
// this mode thing will be turned into a switch statement
switch ( mode )
{
// OR
case 0 :
{
state = 0;
std::vector<Device::Control*>::const_iterator ci = controls.begin(),
ce = controls.end();
for ( ; ci != ce; ++ci )
state = std::max( state, device->GetInputState( (Device::Input*)*ci ) ); // meh casting
break;
}
// AND
case 1 :
{
// TODO: i think i can remove the if here
state = 1;
bool is_bound = false;
std::vector<Device::Control*>::const_iterator ci = controls.begin(),
ce = controls.end();
for ( ; ci != ce; ++ci )
{
is_bound = true;
state = std::min( state, device->GetInputState( (Device::Input*)*ci ) ); // meh casting
}
if ( !is_bound )
state = 0;
break;
}
// NOT
case 2 :
{
state = 0;
std::vector<Device::Control*>::const_iterator ci = controls.begin(),
ce = controls.end();
for ( ; ci != ce; ++ci )
state = std::max( state, device->GetInputState( (Device::Input*)*ci ) ); // meh casting
state = std::max( 0.0, 1.0 - state );
break;
}
}
return std::min( 1.0f, state * range );
}
//
// OutputReference :: State
//
// set the state of all binded outputs
// overrides ControlReference::State .. combined them so i could make the gui simple / inputs == same as outputs one list
// i was lazy and it works so watever
//
ControlState ControllerInterface::OutputReference::State( const ControlState state )
{
std::vector<Device::Control*>::iterator ci = controls.begin(),
ce = controls.end();
for ( ; ci != ce; ++ci )
device->SetOutputState( (Device::Output*)*ci, state * range ); // casting again
return state; // just return the output, watever
}
//
// DeviceQualifier :: ToString
//
// get string from a device qualifier / serialize
//
std::string ControllerInterface::DeviceQualifier::ToString() const
{
if ( source.empty() && (cid < 0) && name.empty() )
return "";
std::ostringstream ss;
ss << source << '/';
if ( cid > -1 )
ss << cid;
ss << '/' << name;
return ss.str();
}
//
// DeviceQualifier :: FromString
//
// set a device qualifier from a string / unserialize
//
void ControllerInterface::DeviceQualifier::FromString(const std::string& str)
{
std::istringstream ss(str);
// good
std::getline( ss, source = "", '/' );
// dum
std::getline( ss, name, '/' );
std::istringstream(name) >> (cid = -1);
// good
std::getline( ss, name = "");
}
//
// DeviceQualifier :: FromDevice
//
// set a device qualifier from a device
//
void ControllerInterface::DeviceQualifier::FromDevice(const ControllerInterface::Device* const dev)
{
name = dev->GetName();
cid = dev->GetId();
source= dev->GetSource();
}
//
// DeviceQualifier = = Device*
//
// check if a device matches a device qualifier
//
bool ControllerInterface::DeviceQualifier::operator==(const ControllerInterface::Device* const dev) const
{
return (dev->GetName() == name) && (dev->GetId() == cid) && (dev->GetSource() == source);
}
//
// ControlQualifier = FromControl
//
// set a control qualifier from a device control
//
void ControllerInterface::ControlQualifier::FromControl(const ControllerInterface::Device::Control* const c)
{
// hardly needs a function for this
name = c->GetName();
}
//
// ControlQualifier = = Device :: Control*
//
// check if a control qualifier matches a device control
// also |control1|control2| form, || matches all
//
bool ControllerInterface::ControlQualifier::operator==(const ControllerInterface::Device::Control* const control) const
{
if ( name.size() )
{
if ( '|' == name[0] && '|' == (*name.rbegin()) ) // check if using |button1|button2| format
{
return ( name.find( '|' + control->GetName() + '|' ) != name.npos || "||" == name );
}
}
return (control->GetName() == name);
}
//
// UpdateReference
//
// updates a controlreference's binded devices then update binded controls
// need to call this after changing a device qualifier on a control reference
// if the device qualifier hasnt changed, the below functions: "UpdateControls" can be used
//
void ControllerInterface::UpdateReference( ControllerInterface::ControlReference* ref )
{
ref->device = NULL;
std::vector<Device*>::const_iterator d = m_devices.begin(),
e = m_devices.end();
for ( ; d!=e; ++d )
if ( ref->device_qualifier == *d )
{
ref->device = *d;
break;
}
ref->UpdateControls();
}
//
// InputReference :: UpdateControls
//
// after changing a control qualifier, need to call this to rebind the new matching controls
//
void ControllerInterface::InputReference::UpdateControls()
{
controls.clear();
if ( device )
{
std::vector<Device::Input*>::const_iterator i = device->Inputs().begin(),
e = device->Inputs().end();
for ( ;i != e; ++i )
if ( control_qualifier == *i )
controls.push_back( *i );
}
}
//
// OutputReference :: UpdateControls
//
// same as the inputRef version
// after changing a control qualifier, need to call this to rebind the new matching controls
//
void ControllerInterface::OutputReference::UpdateControls()
{
controls.clear();
if ( device )
{
std::vector<Device::Output*>::const_iterator i = device->Outputs().begin(),
e = device->Outputs().end();
for ( ;i != e; ++i )
if ( control_qualifier == *i )
controls.push_back( *i );
}
}
//
// InputReference :: Detect
//
// wait for input on all binded devices
// supports waiting for n number of inputs
// supports not detecting inputs that were held down at the time of Detect start,
// which is useful for those crazy flightsticks that have certain buttons that are always held down
// or some crazy axes or something
// upon input, set control qualifier, update controls and return true
// else return false
//
bool ControllerInterface::InputReference::Detect( const unsigned int ms, const unsigned int count )
{
unsigned int time = 0;
// don't wait if we don't have a device
if ( device )
{
bool* const states = new bool[device->Inputs().size()];
std::vector<Device::Input*>::const_iterator i = device->Inputs().begin(),
e = device->Inputs().end();
for ( unsigned int n=0;i != e; ++i,++n )
states[n] = ( device->GetInputState( *i ) > INPUT_DETECT_THRESHOLD );
std::vector<Device::Control*> detected;
while ( (time < ms) && (detected.size() < count) )
{
device->UpdateInput();
i = device->Inputs().begin();
e = device->Inputs().end();
for ( unsigned int n=0;i != e; ++i,++n )
{
if ( device->GetInputState( *i ) > INPUT_DETECT_THRESHOLD )
{
if ( false == states[n] )
if ( std::find( detected.begin(), detected.end(), *i ) == detected.end() )
detected.push_back( *i );
}
else
states[n] = false;
}
Common::SleepCurrentThread( 10 ); time += 10;
}
delete states;
if ( detected.size() == count )
{
controls = detected;
if ( controls.size() > 1 )
{
control_qualifier.name = '|';
std::vector<Device::Control*>::const_iterator c_i = controls.begin(),
c_e = controls.end();
for ( ; c_i != c_e; ++c_i )
control_qualifier.name += (*c_i)->GetName() + '|';
}
else
control_qualifier.FromControl( controls[0] );
return true;
}
}
return false;
}
//
// OutputReference :: Detect
//
// totally different from the inputReference detect / i have them combined so it was simplier to make the gui.
// the gui doesnt know the difference between an input and an output / its odd but i was lazy and it was easy
//
// set all binded outputs to <range> power for x milliseconds return false
//
bool ControllerInterface::OutputReference::Detect( const unsigned int ms, const unsigned int ignored )
{
// dont hang if we dont even have any controls mapped
if ( controls.size() )
{
State( 1 );
unsigned int slept = 0;
// this loop is to make stuff like flashing keyboard LEDs work
while ( ms > ( slept += 10 ) )
{
device->UpdateOutput();
Common::SleepCurrentThread( 10 );
}
State( 0 );
device->UpdateOutput();
}
return false;
}
@@ -0,0 +1,253 @@
#ifndef _DEVICEINTERFACE_H_
#define _DEVICEINTERFACE_H_
#include <vector>
#include <string>
#include <sstream>
#include <map>
#include <algorithm>
#include "Common.h"
// enable disable sources
#ifdef _WIN32
#define CIFACE_USE_XINPUT
#define CIFACE_USE_DIRECTINPUT_JOYSTICK
#define CIFACE_USE_DIRECTINPUT_KBM
#define CIFACE_USE_DIRECTINPUT
#endif
#if defined(HAVE_X11) && HAVE_X11
// Xlib is not tested at all currently, it is like 80% complete at least though
#define CIFACE_USE_XLIB
#endif
#ifndef CIFACE_USE_DIRECTINPUT_JOYSTICK
#define CIFACE_USE_SDL
#endif
#if defined(__APPLE__)
//#define CIFACE_USE_OSX
#endif
// idk in case i wanted to change it to double or somethin, idk what's best
typedef float ControlState;
//
// ControllerInterface
//
// some crazy shit i made to control different device inputs and outputs
// from lots of different sources, hopefully more easily
//
class ControllerInterface
{
public:
//
// Device
//
// Pretty obviously, a device class
//
class Device
{
public:
//
// Control
//
// control includes inputs and outputs
//
class Control // input or output
{
public:
virtual std::string GetName() const = 0;
};
//
// Input
//
// an input on a device
//
class Input : public Control
{
public:
virtual ~Input() {}
};
//
// Output
//
// guess wut it is, yup and output
//
class Output : public Control
{
public:
virtual ~Output() {}
};
virtual ~Device();
virtual std::string GetName() const = 0;
virtual int GetId() const = 0;
virtual std::string GetSource() const = 0;
virtual ControlState GetInputState( const Input* const input ) = 0;
virtual void SetOutputState( const Output* const output, const ControlState state ) = 0;
virtual bool UpdateInput() = 0;
virtual bool UpdateOutput() = 0;
virtual void ClearInputState();
const std::vector< Input* >& Inputs();
const std::vector< Output* >& Outputs();
protected:
std::vector<Input*> inputs;
std::vector<Output*> outputs;
};
//
// DeviceQualifier
//
// device qualifier used to match devices
// currently has ( source, id, name ) properties which match a device
//
class DeviceQualifier
{
public:
DeviceQualifier() : cid(-1){}
DeviceQualifier( const std::string& _source, const int _id, const std::string& _name )
: source(_source), cid(_id), name(_name) {}
bool operator==(const Device* const dev) const;
void FromDevice(const Device* const dev);
void FromString(const std::string& str);
std::string ToString() const;
std::string source;
int cid;
std::string name;
};
//
// ControlQualifier
//
// control qualifier includes input and output qualifiers
// used to match controls on devices, only has name property
// |input1|input2| form as well, || matches anything, might change this to * or something
//
class ControlQualifier
{
public:
ControlQualifier() {};
ControlQualifier( const std::string& _name ) : name(_name) {}
virtual bool operator==(const Device::Control* const in) const;
void FromControl(const Device::Control* const in);
std::string name;
};
//
// InputQualifier
//
// ControlQualifier for inputs
//
class InputQualifier : public ControlQualifier
{
public:
InputQualifier() {};
InputQualifier( const std::string& _name ) : ControlQualifier(_name) {}
};
//
// OutputQualifier
//
// ControlQualifier for outputs
//
class OutputQualifier : public ControlQualifier
{
public:
OutputQualifier() {};
OutputQualifier( const std::string& _name ) : ControlQualifier(_name) {}
};
//
// ControlReference
//
// these are what you create to actually use the inputs, InputReference or OutputReference
// they have a vector < struct { device , vector < controls > } >
//
// after being binded to devices and controls with ControllerInterface::UpdateReference,
// each one can binded to a devices, and 0+ controls the device
// ControlReference can update its own controls when you change its control qualifier
// using ControlReference::UpdateControls but when you change its device qualifer
// you must use ControllerInterface::UpdateReference
//
class ControlReference
{
public:
ControlReference( const bool _is_input ) : range(1), is_input(_is_input), device(NULL) {}
virtual ControlState State( const ControlState state = 0 ) = 0;
virtual bool Detect( const unsigned int ms, const unsigned int count = 1 ) = 0;
virtual void UpdateControls() = 0;
ControlState range;
DeviceQualifier device_qualifier;
ControlQualifier control_qualifier;
const bool is_input;
Device* device;
std::vector<Device::Control*> controls;
};
//
// InputReference
//
// control reference for inputs
//
class InputReference : public ControlReference
{
public:
InputReference() : ControlReference( true ) {}
ControlState State( const ControlState state );
bool Detect( const unsigned int ms, const unsigned int count );
void UpdateControls();
unsigned int mode;
};
//
// OutputReference
//
// control reference for outputs
//
class OutputReference : public ControlReference
{
public:
OutputReference() : ControlReference( false ) {}
ControlState State( const ControlState state );
bool Detect( const unsigned int ms, const unsigned int count );
void UpdateControls();
};
ControllerInterface() : m_is_init(false) {}
void SetHwnd( void* const hwnd );
void Init();
void DeInit();
bool IsInit();
void UpdateReference( ControlReference* control );
bool UpdateInput();
bool UpdateOutput();
const std::vector<Device*>& Devices();
private:
bool m_is_init;
std::vector<Device*> m_devices;
void* m_hwnd;
};
#endif
@@ -0,0 +1,35 @@
#include "../ControllerInterface.h"
#ifdef CIFACE_USE_DIRECTINPUT
#include "DirectInput.h"
#pragma comment(lib, "Dinput8.lib")
#pragma comment(lib, "dxguid.lib")
namespace ciface
{
namespace DirectInput
{
void Init( std::vector<ControllerInterface::Device*>& devices/*, HWND hwnd*/ )
{
IDirectInput8* idi8;
if ( DI_OK != DirectInput8Create( GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (LPVOID*)&idi8, NULL ) )
return;
#ifdef CIFACE_USE_DIRECTINPUT_KBM
InitKeyboardMouse( idi8, devices );
#endif
#ifdef CIFACE_USE_DIRECTINPUT_JOYSTICK
InitJoystick( idi8, devices/*, hwnd*/ );
#endif
idi8->Release();
}
}
}
#endif
@@ -0,0 +1,29 @@
#ifndef _CIFACE_DIRECTINPUT_H_
#define _CIFACE_DIRECTINPUT_H_
#include "../ControllerInterface.h"
#define DIRECTINPUT_VERSION 0x0800
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <Windows.h>
#include <dinput.h>
#ifdef CIFACE_USE_DIRECTINPUT_JOYSTICK
#include "DirectInputJoystick.h"
#endif
#ifdef CIFACE_USE_DIRECTINPUT_KBM
#include "DirectInputKeyboardMouse.h"
#endif
namespace ciface
{
namespace DirectInput
{
void Init( std::vector<ControllerInterface::Device*>& devices/*, HWND hwnd*/ );
}
}
#endif
@@ -0,0 +1,514 @@
#include "../ControllerInterface.h"
#ifdef CIFACE_USE_DIRECTINPUT_JOYSTICK
#include "DirectInputJoystick.h"
namespace ciface
{
namespace DirectInput
{
#ifdef NO_DUPLICATE_DINPUT_XINPUT
//-----------------------------------------------------------------------------
// Modified some MSDN code to get all the XInput device GUID.Data1 values in a vector,
// faster than checking all the devices for each DirectInput device, like MSDN says to do
//-----------------------------------------------------------------------------
void GetXInputGUIDS( std::vector<DWORD>& guids )
{
#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
IWbemLocator* pIWbemLocator = NULL;
IEnumWbemClassObject* pEnumDevices = NULL;
IWbemClassObject* pDevices[20] = {0};
IWbemServices* pIWbemServices = NULL;
BSTR bstrNamespace = NULL;
BSTR bstrDeviceID = NULL;
BSTR bstrClassName = NULL;
DWORD uReturned = 0;
VARIANT var;
HRESULT hr;
// CoInit if needed
hr = CoInitialize(NULL);
bool bCleanupCOM = SUCCEEDED(hr);
// Create WMI
hr = CoCreateInstance( __uuidof(WbemLocator),
NULL,
CLSCTX_INPROC_SERVER,
__uuidof(IWbemLocator),
(LPVOID*) &pIWbemLocator);
if( FAILED(hr) || pIWbemLocator == NULL )
goto LCleanup;
bstrNamespace = SysAllocString( L"\\\\.\\root\\cimv2" );if( bstrNamespace == NULL ) goto LCleanup;
bstrClassName = SysAllocString( L"Win32_PNPEntity" ); if( bstrClassName == NULL ) goto LCleanup;
bstrDeviceID = SysAllocString( L"DeviceID" ); if( bstrDeviceID == NULL ) goto LCleanup;
// Connect to WMI
hr = pIWbemLocator->ConnectServer( bstrNamespace, NULL, NULL, 0L, 0L, NULL, NULL, &pIWbemServices );
if( FAILED(hr) || pIWbemServices == NULL )
goto LCleanup;
// Switch security level to IMPERSONATE.
CoSetProxyBlanket( pIWbemServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL,
RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE );
hr = pIWbemServices->CreateInstanceEnum( bstrClassName, 0, NULL, &pEnumDevices );
if( FAILED(hr) || pEnumDevices == NULL )
goto LCleanup;
// Loop over all devices
while( true )
{
// Get 20 at a time
hr = pEnumDevices->Next( 10000, 20, pDevices, &uReturned );
if( FAILED(hr) || uReturned == 0 )
break;
for( UINT iDevice=0; iDevice<uReturned; ++iDevice )
{
// For each device, get its device ID
hr = pDevices[iDevice]->Get( bstrDeviceID, 0L, &var, NULL, NULL );
if( SUCCEEDED( hr ) && var.vt == VT_BSTR && var.bstrVal != NULL )
{
// Check if the device ID contains "IG_". If it does, then it's an XInput device
// This information can not be found from DirectInput
if( wcsstr( var.bstrVal, L"IG_" ) )
{
// If it does, then get the VID/PID from var.bstrVal
DWORD dwPid = 0, dwVid = 0;
WCHAR* strVid = wcsstr( var.bstrVal, L"VID_" );
if( strVid && swscanf( strVid, L"VID_%4X", &dwVid ) != 1 )
dwVid = 0;
WCHAR* strPid = wcsstr( var.bstrVal, L"PID_" );
if( strPid && swscanf( strPid, L"PID_%4X", &dwPid ) != 1 )
dwPid = 0;
// Compare the VID/PID to the DInput device
DWORD dwVidPid = MAKELONG( dwVid, dwPid );
guids.push_back( dwVidPid );
//bIsXinputDevice = true;
}
}
SAFE_RELEASE( pDevices[iDevice] );
}
}
LCleanup:
if(bstrNamespace)
SysFreeString(bstrNamespace);
if(bstrDeviceID)
SysFreeString(bstrDeviceID);
if(bstrClassName)
SysFreeString(bstrClassName);
for( UINT iDevice=0; iDevice<20; iDevice++ )
SAFE_RELEASE( pDevices[iDevice] );
SAFE_RELEASE( pEnumDevices );
SAFE_RELEASE( pIWbemLocator );
SAFE_RELEASE( pIWbemServices );
if( bCleanupCOM )
CoUninitialize();
}
#endif
std::string TStringToString( const std::basic_string<TCHAR>& in )
{
const int size = WideCharToMultiByte( CP_UTF8, 0, in.data(), int(in.length()), NULL, 0, NULL, NULL );
if ( 0 == size )
return "";
char* const data = new char[size];
WideCharToMultiByte( CP_UTF8, 0, in.data(), int(in.length()), data, size, NULL, NULL );
const std::string out( data, size );
delete[] data;
return out;
}
//BOOL CALLBACK DIEnumEffectsCallback( LPCDIEFFECTINFO pdei, LPVOID pvRef )
//{
// ((std::vector<DIEFFECTINFO>*)pvRef)->push_back( *pdei );
// return DIENUM_CONTINUE;
//}
BOOL CALLBACK DIEnumDeviceObjectsCallback( LPCDIDEVICEOBJECTINSTANCE lpddoi, LPVOID pvRef )
{
((std::vector<DIDEVICEOBJECTINSTANCE>*)pvRef)->push_back( *lpddoi );
return DIENUM_CONTINUE;
}
BOOL CALLBACK DIEnumDevicesCallback( LPCDIDEVICEINSTANCE lpddi, LPVOID pvRef )
{
((std::vector<DIDEVICEINSTANCE>*)pvRef)->push_back( *lpddi );
return DIENUM_CONTINUE;
}
void InitJoystick( IDirectInput8* const idi8, std::vector<ControllerInterface::Device*>& devices/*, HWND hwnd*/ )
{
std::vector<DIDEVICEINSTANCE> joysticks;
idi8->EnumDevices( DI8DEVCLASS_GAMECTRL, DIEnumDevicesCallback, (LPVOID)&joysticks, DIEDFL_ATTACHEDONLY );
// just a struct with an int that is set to ZERO by default
struct ZeroedInt{ZeroedInt():value(0){}unsigned int value;};
// this is used to number the joysticks
// multiple joysticks with the same name shall get unique ids starting at 0
std::map< std::basic_string<TCHAR>, ZeroedInt > name_counts;
#ifdef NO_DUPLICATE_DINPUT_XINPUT
std::vector<DWORD> xinput_guids;
GetXInputGUIDS( xinput_guids );
#endif
std::vector<DIDEVICEINSTANCE>::iterator i = joysticks.begin(),
e = joysticks.end();
for ( ; i!=e; ++i )
{
#ifdef NO_DUPLICATE_DINPUT_XINPUT
// skip XInput Devices
if ( std::find( xinput_guids.begin(), xinput_guids.end(), i->guidProduct.Data1 ) != xinput_guids.end() )
continue;
#endif
// TODO: this has potential to mess up on createdev or setdatafmt failure
LPDIRECTINPUTDEVICE8 js_device;
if ( DI_OK == idi8->CreateDevice( i->guidInstance, &js_device, NULL ) )
if ( DI_OK == js_device->SetDataFormat( &c_dfDIJoystick ) )
// using foregroundwindow seems like a hack
if ( DI_OK != js_device->SetCooperativeLevel( GetForegroundWindow(), DISCL_BACKGROUND | DISCL_EXCLUSIVE ) )
{
// fall back to non-exclusive mode, with no rumble
if ( DI_OK != js_device->SetCooperativeLevel( NULL, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE ) )
{
js_device->Release();
continue;
}
}
if ( DI_OK == js_device->Acquire() )
{
Joystick* js = new Joystick( /*&*i, */js_device, name_counts[i->tszInstanceName].value++ );
// only add if it has some inputs/outpus
if ( js->Inputs().size() || js->Outputs().size() )
devices.push_back( js );
else
delete js;
}
else
js_device->Release();
}
}
Joystick::Joystick( /*const LPCDIDEVICEINSTANCE lpddi, */const LPDIRECTINPUTDEVICE8 device, const unsigned int index )
: m_device(device)
, m_index(index)
//, m_name(TStringToString(lpddi->tszInstanceName))
{
// get joystick caps
DIDEVCAPS js_caps;
ZeroMemory( &js_caps, sizeof(js_caps) );
js_caps.dwSize = sizeof(js_caps);
m_device->GetCapabilities(&js_caps);
// max of 32 buttons and 4 hats / the limit of the data format i am using
js_caps.dwButtons = std::min((DWORD)32, js_caps.dwButtons);
js_caps.dwPOVs = std::min((DWORD)4, js_caps.dwPOVs);
m_must_poll = ( ( js_caps.dwFlags & DIDC_POLLEDDATAFORMAT ) > 0 );
// buttons
for ( unsigned int i = 0; i < js_caps.dwButtons; ++i )
inputs.push_back( new Button( i ) );
// hats
for ( unsigned int i = 0; i < js_caps.dwPOVs; ++i )
{
// each hat gets 4 input instances associated with it, (up down left right)
for ( unsigned int d = 0; d<4; ++d )
inputs.push_back( new Hat( i, d ) );
}
// get up to 6 axes and 2 sliders
std::vector<DIDEVICEOBJECTINSTANCE> axes;
unsigned int cur_slider = 0;
m_device->EnumObjects( DIEnumDeviceObjectsCallback, (LPVOID)&axes, DIDFT_AXIS );
// going in reverse leaves the list more organized in the end for me :/
std::vector<DIDEVICEOBJECTINSTANCE>::const_reverse_iterator i = axes.rbegin(),
e = axes.rend();
for( ; i!=e; ++i )
{
DIPROPRANGE range;
ZeroMemory( &range, sizeof(range ) );
range.diph.dwSize = sizeof(range);
range.diph.dwHeaderSize = sizeof(range.diph);
range.diph.dwHow = DIPH_BYID;
range.diph.dwObj = i->dwType;
// try to set some nice power of 2 values (8192)
range.lMin = -(1<<13);
range.lMax = (1<<13);
// but i guess not all devices support setting range
m_device->SetProperty( DIPROP_RANGE, &range.diph );
// so i getproperty right afterward incase it didn't set :P
if ( DI_OK == m_device->GetProperty( DIPROP_RANGE, &range.diph ) )
{
int offset = -1;
const GUID type = i->guidType;
// figure out which axis this is
if ( type == GUID_XAxis )
offset = 0;
else if ( type == GUID_YAxis )
offset = 1;
else if ( type == GUID_ZAxis )
offset = 2;
else if ( type == GUID_RxAxis )
offset = 3;
else if ( type == GUID_RyAxis )
offset = 4;
else if ( type == GUID_RzAxis )
offset = 5;
else if ( type == GUID_Slider )
if ( cur_slider < 2 )
offset = 6 + cur_slider++;
if ( offset >= 0 )
{
const LONG base = (range.lMin + range.lMax) / 2;
// each axis gets a negative and a positive input instance associated with it
inputs.push_back( new Axis( offset, base, range.lMin-base ) );
inputs.push_back( new Axis( offset, base, range.lMax-base ) );
}
}
}
// get supported ff effects
std::vector<DIDEVICEOBJECTINSTANCE> objects;
m_device->EnumObjects( DIEnumDeviceObjectsCallback, (LPVOID)&objects, DIDFT_AXIS );
// got some ff axes or something
if ( objects.size() )
{
// temporary
DWORD rgdwAxes[] = { DIJOFS_X, DIJOFS_Y };
LONG rglDirection[] = { 0, 0 };
DICONSTANTFORCE cf = { 0 };
DIEFFECT eff;
ZeroMemory( &eff, sizeof( DIEFFECT ) );
eff.dwSize = sizeof( DIEFFECT );
eff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS;
eff.dwDuration = INFINITE;
eff.dwGain = DI_FFNOMINALMAX;
eff.dwTriggerButton = DIEB_NOTRIGGER;
eff.cAxes = std::min( (DWORD)2, (DWORD)objects.size() );
eff.rgdwAxes = rgdwAxes;
eff.rglDirection = rglDirection;
eff.cbTypeSpecificParams = sizeof( DICONSTANTFORCE );
eff.lpvTypeSpecificParams = &cf;
LPDIRECTINPUTEFFECT pEffect;
if ( DI_OK == m_device->CreateEffect( GUID_ConstantForce, &eff, &pEffect, NULL ) )
{
// temp
outputs.push_back( new Force( 0 ) );
m_state_out.push_back( EffectState( pEffect ) );
}
}
// disable autocentering
if ( outputs.size() )
{
DIPROPDWORD dipdw;
dipdw.diph.dwSize = sizeof( DIPROPDWORD );
dipdw.diph.dwHeaderSize = sizeof( DIPROPHEADER );
dipdw.diph.dwObj = 0;
dipdw.diph.dwHow = DIPH_DEVICE;
dipdw.dwData = FALSE;
m_device->SetProperty( DIPROP_AUTOCENTER, &dipdw.diph );
}
ClearInputState();
}
Joystick::~Joystick()
{
// release the ff effect iface's
std::vector<EffectState>::iterator i = m_state_out.begin(),
e = m_state_out.end();
for ( ; i!=e; ++i )
{
i->iface->Stop();
i->iface->Unload();
i->iface->Release();
}
m_device->Unacquire();
m_device->Release();
}
void Joystick::ClearInputState()
{
ZeroMemory(&m_state_in, sizeof(m_state_in));
// set hats to center
memset( m_state_in.rgdwPOV, 0xFF, sizeof(m_state_in.rgdwPOV) );
}
std::string Joystick::GetName() const
{
DIPROPSTRING str;
ZeroMemory( &str, sizeof(str) );
str.diph.dwSize = sizeof(str);
str.diph.dwHeaderSize = sizeof(str.diph);
str.diph.dwHow = DIPH_DEVICE;
m_device->GetProperty( DIPROP_PRODUCTNAME, &str.diph );
return TStringToString( str.wsz );
//return m_name;
}
int Joystick::GetId() const
{
return m_index;
}
std::string Joystick::GetSource() const
{
return "DirectInput";
}
// update IO
bool Joystick::UpdateInput()
{
if ( m_must_poll )
m_device->Poll();
//return false;
HRESULT hr = m_device->GetDeviceState( sizeof(m_state_in), &m_state_in );
// try reacquire if input lost
if ( DIERR_INPUTLOST == hr )
hr = m_device->Acquire();
return ( DI_OK == hr );
}
bool Joystick::UpdateOutput()
{
// temporary
size_t ok_count = 0;
std::vector<EffectState>::iterator i = m_state_out.begin(),
e = m_state_out.end();
for ( ; i!=e; ++i )
{
if ( i->changed )
{
i->changed = false;
DICONSTANTFORCE cf;
cf.lMagnitude = LONG(10000 * i->magnitude);
if ( cf.lMagnitude )
{
DIEFFECT eff;
ZeroMemory( &eff, sizeof( eff ) );
eff.dwSize = sizeof( DIEFFECT );
eff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS;
eff.cbTypeSpecificParams = sizeof( cf );
eff.lpvTypeSpecificParams = &cf;
// set params and start effect
ok_count += ( DI_OK == i->iface->SetParameters( &eff, DIEP_TYPESPECIFICPARAMS | DIEP_START ) );
}
else
ok_count += ( DI_OK == i->iface->Stop() );
}
else
++ok_count;
}
return ( m_state_out.size() == ok_count );
}
// get name
std::string Joystick::Button::GetName() const
{
std::ostringstream ss;
ss << "Button " << m_index;
return ss.str();
}
std::string Joystick::Axis::GetName() const
{
std::ostringstream ss;
// axis
if ( m_index < 6 )
{
ss << "Axis " << "XYZ"[m_index%3];
if ( m_index > 2 )
ss << 'r';
}
// slider
else
ss << "Slider " << m_index-6;
ss << ( m_range>0 ? '+' : '-' );
return ss.str();
}
std::string Joystick::Hat::GetName() const
{
std::ostringstream ss;
ss << "Hat " << m_index << ' ' << "NESW"[m_direction];
return ss.str();
}
std::string Joystick::Force::GetName() const
{
// temporary
return "Constant";
}
// get / set state
ControlState Joystick::GetInputState( const ControllerInterface::Device::Input* const input )
{
return ((Input*)input)->GetState( &m_state_in );
}
void Joystick::SetOutputState( const ControllerInterface::Device::Output* const output, const ControlState state )
{
((Output*)output)->SetState( state, &m_state_out[0] );
}
// get / set state
ControlState Joystick::Axis::GetState( const DIJOYSTATE* const joystate )
{
return std::max( 0.0f, ControlState((&joystate->lX)[m_index]-m_base) / m_range );
}
ControlState Joystick::Button::GetState( const DIJOYSTATE* const joystate )
{
return ControlState( joystate->rgbButtons[m_index] > 0 );
}
ControlState Joystick::Hat::GetState( const DIJOYSTATE* const joystate )
{
// can this func be simplified ?
const DWORD val = joystate->rgdwPOV[m_index];
// hat centered code from msdn
if ( 0xFFFF == LOWORD(val) )
return 0;
return ( abs( (int)(val/4500-m_direction*2+8)%8 - 4) > 2 );
}
void Joystick::Force::SetState( const ControlState state, Joystick::EffectState* const joystate )
{
joystate[m_index].magnitude = state;
joystate[m_index].changed = true;
}
}
}
#endif
@@ -0,0 +1,137 @@
#ifndef _CIFACE_DIRECTINPUT_JOYSTICK_H_
#define _CIFACE_DIRECTINPUT_JOYSTICK_H_
#include "../ControllerInterface.h"
#define DIRECTINPUT_VERSION 0x0800
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <Windows.h>
#include <dinput.h>
#ifdef CIFACE_USE_XINPUT
// this takes so long, idk if it should be enabled :(
#define NO_DUPLICATE_DINPUT_XINPUT
#include <wbemidl.h>
#include <oleauto.h>
#endif
namespace ciface
{
namespace DirectInput
{
void InitJoystick( IDirectInput8* const idi8, std::vector<ControllerInterface::Device*>& devices/*, HWND hwnd*/ );
class Joystick : public ControllerInterface::Device
{
friend class ControllerInterface;
friend class ControllerInterface::ControlReference;
protected:
struct EffectState
{
EffectState( LPDIRECTINPUTEFFECT eff ) : changed(0), iface(eff) {}
LPDIRECTINPUTEFFECT iface;
ControlState magnitude;
bool changed;
};
class Input : public ControllerInterface::Device::Input
{
friend class Joystick;
protected:
virtual ControlState GetState( const DIJOYSTATE* const joystate ) = 0;
};
// can probably eliminate this base class
class Output : public ControllerInterface::Device::Output
{
friend class Joystick;
protected:
virtual void SetState( const ControlState state, EffectState* const joystate ) = 0;
};
class Button : public Input
{
friend class Joystick;
public:
std::string GetName() const;
protected:
Button( const unsigned int index ) : m_index(index) {}
ControlState GetState( const DIJOYSTATE* const joystate );
private:
const unsigned int m_index;
};
class Axis : public Input
{
friend class Joystick;
public:
std::string GetName() const;
protected:
Axis( const unsigned int index, const LONG base, const LONG range ) : m_index(index), m_base(base), m_range(range) {}
ControlState GetState( const DIJOYSTATE* const joystate );
private:
const unsigned int m_index;
const LONG m_base;
const LONG m_range;
};
class Hat : public Input
{
friend class Joystick;
public:
std::string GetName() const;
protected:
Hat( const unsigned int index, const unsigned int direction ) : m_index(index), m_direction(direction) {}
ControlState GetState( const DIJOYSTATE* const joystate );
private:
const unsigned int m_index;
const unsigned int m_direction;
};
class Force : public Output
{
friend class Joystick;
public:
std::string GetName() const;
protected:
Force( const unsigned int index ) : m_index(index) {}
void SetState( const ControlState state, EffectState* const joystate );
private:
const unsigned int m_index;
};
bool UpdateInput();
bool UpdateOutput();
ControlState GetInputState( const ControllerInterface::Device::Input* const input );
void SetOutputState( const ControllerInterface::Device::Output* const input, const ControlState state );
void ClearInputState();
public:
Joystick( /*const LPCDIDEVICEINSTANCE lpddi, */const LPDIRECTINPUTDEVICE8 device, const unsigned int index );
~Joystick();
std::string GetName() const;
int GetId() const;
std::string GetSource() const;
private:
const LPDIRECTINPUTDEVICE8 m_device;
const unsigned int m_index;
//const std::string m_name;
DIJOYSTATE m_state_in;
std::vector<EffectState> m_state_out;
bool m_must_poll;
};
}
}
#endif
@@ -0,0 +1,272 @@
#include "../ControllerInterface.h"
#ifdef CIFACE_USE_DIRECTINPUT_KBM
#include "DirectInputKeyboardMouse.h"
// TODO: maybe add a ClearInputState function to this device
// (lower would be more sensitive) user can lower sensitivity by setting range
// seems decent here ( at 8 ), I dont think anyone would need more sensitive than this
// and user can lower it much farther than they would want to with the range
#define MOUSE_AXIS_SENSITIVITY 8
// if input hasn't been received for this many ms, mouse input will be skipped
// otherwise it is just some crazy value
#define DROP_INPUT_TIME 250
namespace ciface
{
namespace DirectInput
{
struct
{
const BYTE code;
const char* const name;
} named_keys[] =
{
#include "NamedKeys.h"
};
struct
{
const BYTE code;
const char* const name;
} named_lights[] =
{
{ VK_NUMLOCK, "NUM LOCK" },
{ VK_CAPITAL, "CAPS LOCK" },
{ VK_SCROLL, "SCROLL LOCK" }
};
void InitKeyboardMouse( IDirectInput8* const idi8, std::vector<ControllerInterface::Device*>& devices )
{
// mouse and keyboard are a combined device, to allow shift+click and stuff
// if thats dumb, i will make a VirtualDevice class that just uses ranges of inputs/outputs from other devices
// so there can be a separated Keyboard and mouse, as well as combined KeyboardMouse
// TODO: this has potential to not release devices if set datafmt or cooplevel fails
LPDIRECTINPUTDEVICE8 kb_device;
LPDIRECTINPUTDEVICE8 mo_device;
if ( DI_OK == idi8->CreateDevice( GUID_SysKeyboard, &kb_device, NULL ) )
if ( DI_OK == kb_device->SetDataFormat( &c_dfDIKeyboard ) )
if ( DI_OK == kb_device->SetCooperativeLevel( NULL, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE) )
if ( DI_OK == kb_device->Acquire() )
{
if ( DI_OK == idi8->CreateDevice( GUID_SysMouse, &mo_device, NULL ) )
if ( DI_OK == mo_device->SetDataFormat( &c_dfDIMouse2 ) )
if ( DI_OK == mo_device->SetCooperativeLevel( NULL, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE) )
if ( DI_OK == mo_device->Acquire() )
{
devices.push_back( new KeyboardMouse( kb_device, mo_device ) );
return;
}
else
goto release_mouse;
goto unacquire_kb;
}
else
goto release_kb;
release_mouse:
mo_device->Release();
unacquire_kb:
kb_device->Unacquire();
release_kb:
kb_device->Release();
}
KeyboardMouse::~KeyboardMouse()
{
// kb
m_kb_device->Unacquire();
m_kb_device->Release();
// mouse
m_mo_device->Unacquire();
m_mo_device->Release();
}
KeyboardMouse::KeyboardMouse( const LPDIRECTINPUTDEVICE8 kb_device, const LPDIRECTINPUTDEVICE8 mo_device )
: m_kb_device(kb_device)
, m_mo_device(mo_device)
{
m_last_update = wxGetLocalTimeMillis();
ZeroMemory( &m_state_in, sizeof(m_state_in) );
ZeroMemory( m_state_out, sizeof(m_state_out) );
ZeroMemory( &m_current_state_out, sizeof(m_current_state_out) );
// KEYBOARD
// add keys
for ( unsigned int i = 0; i < sizeof(named_keys)/sizeof(*named_keys); ++i )
inputs.push_back( new Key( i ) );
// add lights
for ( unsigned int i = 0; i < sizeof(named_lights)/sizeof(*named_lights); ++i )
outputs.push_back( new Light( i ) );
// MOUSE
// get caps
DIDEVCAPS mouse_caps;
ZeroMemory( &mouse_caps, sizeof(mouse_caps) );
mouse_caps.dwSize = sizeof(mouse_caps);
m_mo_device->GetCapabilities(&mouse_caps);
// mouse buttons
for ( unsigned int i = 0; i < mouse_caps.dwButtons; ++i )
inputs.push_back( new Button( i ) );
// mouse axes
for ( unsigned int i = 0; i < mouse_caps.dwAxes; ++i )
{
// each axis gets a negative and a positive input instance associated with it
inputs.push_back( new Axis( i, (2==i) ? -1 : -MOUSE_AXIS_SENSITIVITY ) );
inputs.push_back( new Axis( i, -(2==i) ? 1 : MOUSE_AXIS_SENSITIVITY ) );
}
}
bool KeyboardMouse::UpdateInput()
{
DIMOUSESTATE2 tmp_mouse;
// if mouse position hasn't been updated in a short while, skip a dev state
wxLongLong cur_time = wxGetLocalTimeMillis();
if ( cur_time - m_last_update > DROP_INPUT_TIME )
{
// set axes to zero
ZeroMemory( &m_state_in.mouse, sizeof(m_state_in.mouse) );
// skip this input state
m_mo_device->GetDeviceState( sizeof(tmp_mouse), &tmp_mouse );
}
m_last_update = cur_time;
if ( DI_OK == m_kb_device->GetDeviceState( sizeof(m_state_in.keyboard), &m_state_in.keyboard )
&& DI_OK == m_mo_device->GetDeviceState( sizeof(tmp_mouse), &tmp_mouse ) )
{
// need to smooth out the axes, otherwise it doesnt work for shit
for ( unsigned int i = 0; i < 3; ++i )
((&m_state_in.mouse.lX)[i] += (&tmp_mouse.lX)[i]) /= 2;
// copy over the buttons
memcpy( m_state_in.mouse.rgbButtons, tmp_mouse.rgbButtons, sizeof(m_state_in.mouse.rgbButtons) );
return true;
}
else
return false;
}
bool KeyboardMouse::UpdateOutput()
{
class KInput : public INPUT
{
public:
KInput( const unsigned char key, const bool up = false )
{
memset( this, 0, sizeof(*this) );
type = INPUT_KEYBOARD;
ki.wVk = key;
if (up) ki.dwFlags = KEYEVENTF_KEYUP;
}
};
std::vector< KInput > kbinputs;
for ( unsigned int i = 0; i < sizeof(m_state_out)/sizeof(*m_state_out); ++i )
{
bool want_on = false;
if ( m_state_out[i] )
want_on = m_state_out[i] > wxGetLocalTimeMillis() % 255 ; // light should flash when output is 0.5
// lights are set to their original state when output is zero
if ( want_on ^ m_current_state_out[i] )
{
kbinputs.push_back( KInput( named_lights[i].code ) ); // press
kbinputs.push_back( KInput( named_lights[i].code, true ) ); // release
m_current_state_out[i] ^= 1;
}
}
if ( kbinputs.size() )
return ( kbinputs.size() == SendInput( (UINT)kbinputs.size(), &kbinputs[0], sizeof( kbinputs[0] ) ) );
else
return true;
}
std::string KeyboardMouse::GetName() const
{
return "Keyboard Mouse";
}
int KeyboardMouse::GetId() const
{
// should this be -1, idk
return 0;
}
std::string KeyboardMouse::GetSource() const
{
return "DirectInput";
}
ControlState KeyboardMouse::GetInputState( const ControllerInterface::Device::Input* const input )
{
return ( ((Input*)input)->GetState( &m_state_in ) );
}
void KeyboardMouse::SetOutputState( const ControllerInterface::Device::Output* const output, const ControlState state )
{
((Output*)output)->SetState( state, m_state_out );
}
// names
std::string KeyboardMouse::Key::GetName() const
{
return named_keys[m_index].name;
}
std::string KeyboardMouse::Button::GetName() const
{
return std::string("Button ") + char('0'+m_index);
}
std::string KeyboardMouse::Axis::GetName() const
{
std::string tmpstr("Mouse ");
tmpstr += "XYZ"[m_index]; tmpstr += ( m_range>0 ? '+' : '-' );
return tmpstr;
}
std::string KeyboardMouse::Light::GetName() const
{
return named_lights[ m_index ].name;
}
// get/set state
ControlState KeyboardMouse::Key::GetState( const State* const state )
{
return ( state->keyboard[named_keys[m_index].code] > 0 );
}
ControlState KeyboardMouse::Button::GetState( const State* const state )
{
return ( state->mouse.rgbButtons[m_index] > 0 );
}
ControlState KeyboardMouse::Axis::GetState( const State* const state )
{
return std::max( 0.0f, ControlState((&state->mouse.lX)[m_index]) / m_range );
}
void KeyboardMouse::Light::SetState( const ControlState state, unsigned char* const state_out )
{
state_out[ m_index ] = state * 255;
}
}
}
#endif
@@ -0,0 +1,125 @@
#ifndef _CIFACE_DIRECTINPUT_KBM_H_
#define _CIFACE_DIRECTINPUT_KBM_H_
#include "../ControllerInterface.h"
#define DIRECTINPUT_VERSION 0x0800
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <Windows.h>
#include <dinput.h>
#include <wx/stopwatch.h>
#include <wx/utils.h>
namespace ciface
{
namespace DirectInput
{
void InitKeyboardMouse( IDirectInput8* const idi8, std::vector<ControllerInterface::Device*>& devices );
class KeyboardMouse : public ControllerInterface::Device
{
friend class ControllerInterface;
friend class ControllerInterface::ControlReference;
protected:
struct State
{
BYTE keyboard[256];
DIMOUSESTATE2 mouse;
};
class Input : public ControllerInterface::Device::Input
{
friend class KeyboardMouse;
protected:
virtual ControlState GetState( const State* const boardstate ) = 0;
};
class Output : public ControllerInterface::Device::Output
{
friend class KeyboardMouse;
protected:
virtual void SetState( const ControlState state, unsigned char* const state_out ) = 0;
};
class Key : public Input
{
friend class KeyboardMouse;
public:
std::string GetName() const;
protected:
Key( const unsigned int index ) : m_index(index) {}
ControlState GetState( const State* const state );
private:
const unsigned int m_index;
};
class Button : public Input
{
friend class KeyboardMouse;
public:
std::string GetName() const;
protected:
Button( const unsigned int index ) : m_index(index) {}
ControlState GetState( const State* const state );
private:
const unsigned int m_index;
};
class Axis : public Input
{
friend class KeyboardMouse;
public:
std::string GetName() const;
protected:
Axis( const unsigned int index, const LONG range ) : m_index(index), m_range(range) {}
ControlState GetState( const State* const state );
private:
const unsigned int m_index;
const LONG m_range;
};
class Light : public Output
{
friend class KeyboardMouse;
public:
std::string GetName() const;
protected:
Light( const unsigned int index ) : m_index(index) {}
void SetState( const ControlState state, unsigned char* const state_out );
private:
const unsigned int m_index;
};
bool UpdateInput();
bool UpdateOutput();
ControlState GetInputState( const ControllerInterface::Device::Input* const input );
void SetOutputState( const ControllerInterface::Device::Output* const input, const ControlState state );
public:
KeyboardMouse( const LPDIRECTINPUTDEVICE8 kb_device, const LPDIRECTINPUTDEVICE8 mo_device );
~KeyboardMouse();
std::string GetName() const;
int GetId() const;
std::string GetSource() const;
private:
const LPDIRECTINPUTDEVICE8 m_kb_device;
const LPDIRECTINPUTDEVICE8 m_mo_device;
wxLongLong m_last_update;
State m_state_in;
unsigned char m_state_out[3]; // NUM CAPS SCROLL
bool m_current_state_out[3]; // NUM CAPS SCROLL
};
}
}
#endif
@@ -0,0 +1,144 @@
{ DIK_A, "A" },
{ DIK_B, "B" },
{ DIK_C, "C" },
{ DIK_D, "D" },
{ DIK_E, "E" },
{ DIK_F, "F" },
{ DIK_G, "G" },
{ DIK_H, "H" },
{ DIK_I, "I" },
{ DIK_J, "J" },
{ DIK_K, "K" },
{ DIK_L, "L" },
{ DIK_M, "M" },
{ DIK_N, "N" },
{ DIK_O, "O" },
{ DIK_P, "P" },
{ DIK_Q, "Q" },
{ DIK_R, "R" },
{ DIK_S, "S" },
{ DIK_T, "T" },
{ DIK_U, "U" },
{ DIK_V, "V" },
{ DIK_W, "W" },
{ DIK_X, "X" },
{ DIK_Y, "Y" },
{ DIK_Z, "Z" },
{ DIK_0, "0" },
{ DIK_1, "1" },
{ DIK_2, "2" },
{ DIK_3, "3" },
{ DIK_4, "4" },
{ DIK_5, "5" },
{ DIK_6, "6" },
{ DIK_7, "7" },
{ DIK_8, "8" },
{ DIK_9, "9" },
{ DIK_UP, "UP" },
{ DIK_DOWN, "DOWN" },
{ DIK_LEFT, "LEFT" },
{ DIK_RIGHT, "RIGHT" },
{ DIK_ABNT_C1, "ABNT_C1" },
{ DIK_ABNT_C2, "ABNT_C2" },
{ DIK_ADD, "ADD" },
{ DIK_APOSTROPHE, "APOSTROPHE" },
{ DIK_APPS, "APPS" },
{ DIK_AT, "AT" },
{ DIK_AX, "AX" },
{ DIK_BACK, "BACK" },
{ DIK_BACKSLASH, "BACKSLASH" },
{ DIK_CALCULATOR, "CALCULATOR" },
{ DIK_CAPITAL, "CAPITAL" },
{ DIK_COLON, "COLON" },
{ DIK_COMMA, "COMMA" },
{ DIK_CONVERT, "CONVERT" },
{ DIK_DECIMAL, "DECIMAL" },
{ DIK_DELETE, "DELETE" },
{ DIK_DIVIDE, "DIVIDE" },
{ DIK_EQUALS, "EQUALS" },
{ DIK_ESCAPE, "ESCAPE" },
{ DIK_F1, "F1" },
{ DIK_F2, "F2" },
{ DIK_F3, "F3" },
{ DIK_F4, "F4" },
{ DIK_F5, "F5" },
{ DIK_F6, "F6" },
{ DIK_F7, "F7" },
{ DIK_F8, "F8" },
{ DIK_F9, "F9" },
{ DIK_F10, "F10" },
{ DIK_F11, "F11" },
{ DIK_F12, "F12" },
{ DIK_F13, "F13" },
{ DIK_F14, "F14" },
{ DIK_F15, "F15" },
{ DIK_GRAVE, "GRAVE" },
{ DIK_HOME, "HOME" },
{ DIK_END, "END" },
{ DIK_INSERT, "INSERT" },
{ DIK_KANA, "KANA" },
{ DIK_KANJI, "KANJI" },
{ DIK_MAIL, "MAIL" },
{ DIK_MEDIASELECT, "MEDIASELECT" },
{ DIK_MEDIASTOP, "MEDIASTOP" },
{ DIK_MINUS, "MINUS" },
{ DIK_MULTIPLY, "MULTIPLY" },
{ DIK_MUTE, "MUTE" },
{ DIK_MYCOMPUTER, "MYCOMPUTER" },
{ DIK_NEXTTRACK, "NEXTTRACK" },
{ DIK_NOCONVERT, "NOCONVERT" },
{ DIK_NUMLOCK, "NUMLOCK" },
{ DIK_NUMPAD0, "NUMPAD0" },
{ DIK_NUMPAD1, "NUMPAD1" },
{ DIK_NUMPAD2, "NUMPAD2" },
{ DIK_NUMPAD3, "NUMPAD3" },
{ DIK_NUMPAD4, "NUMPAD4" },
{ DIK_NUMPAD5, "NUMPAD5" },
{ DIK_NUMPAD6, "NUMPAD6" },
{ DIK_NUMPAD7, "NUMPAD7" },
{ DIK_NUMPAD8, "NUMPAD8" },
{ DIK_NUMPAD9, "NUMPAD9" },
{ DIK_NUMPADCOMMA, "NUMPADCOMMA" },
{ DIK_NUMPADENTER, "NUMPADENTER" },
{ DIK_NUMPADEQUALS, "NUMPADEQUALS" },
{ DIK_OEM_102, "OEM_102" },
{ DIK_PAUSE, "PAUSE" },
{ DIK_PERIOD, "PERIOD" },
{ DIK_PLAYPAUSE, "PLAYPAUSE" },
{ DIK_POWER, "POWER" },
{ DIK_PREVTRACK, "PREVTRACK" },
{ DIK_PRIOR, "PRIOR" },
{ DIK_NEXT, "NEXT" },
{ DIK_RETURN, "RETURN" },
{ DIK_LBRACKET, "LBRACKET" },
{ DIK_RBRACKET, "RBRACKET" },
{ DIK_LCONTROL, "LCONTROL" },
{ DIK_RCONTROL, "RCONTROL" },
{ DIK_LMENU, "LMENU" },
{ DIK_RMENU, "RMENU" },
{ DIK_LSHIFT, "LSHIFT" },
{ DIK_RSHIFT, "RSHIFT" },
{ DIK_LWIN, "LWIN" },
{ DIK_RWIN, "RWIN" },
{ DIK_SCROLL, "SCROLL" },
{ DIK_SEMICOLON, "SEMICOLON" },
{ DIK_SLASH, "SLASH" },
{ DIK_SLEEP, "SLEEP" },
{ DIK_SPACE, "SPACE" },
{ DIK_STOP, "STOP" },
{ DIK_SUBTRACT, "SUBTRACT" },
{ DIK_SYSRQ, "SYSRQ" },
{ DIK_TAB, "TAB" },
{ DIK_UNDERLINE, "UNDERLINE" },
{ DIK_UNLABELED, "UNLABELED" },
{ DIK_VOLUMEDOWN, "VOLUMEDOWN" },
{ DIK_VOLUMEUP, "VOLUMEUP" },
{ DIK_WAKE, "WAKE" },
{ DIK_WEBBACK, "WEBBACK" },
{ DIK_WEBFAVORITES, "WEBFAVORITES" },
{ DIK_WEBFORWARD, "WEBFORWARD" },
{ DIK_WEBHOME, "WEBHOME" },
{ DIK_WEBREFRESH, "WEBREFRESH" },
{ DIK_WEBSEARCH, "WEBSEARCH" },
{ DIK_WEBSTOP, "WEBSTOP" },
{ DIK_YEN, "YEN" },
@@ -0,0 +1,266 @@
#include "../ControllerInterface.h"
#ifdef CIFACE_USE_SDL
#include "SDL.h"
#ifdef _WIN32
#if SDL_VERSION_ATLEAST(1, 3, 0)
#pragma comment(lib, "SDL.1.3.lib")
#else
#pragma comment(lib, "SDL.lib")
#endif
#endif
namespace ciface
{
namespace SDL
{
void Init( std::vector<ControllerInterface::Device*>& devices )
{
if ( SDL_Init( SDL_INIT_FLAGS ) >= 0 )
{
// joysticks
for( int i = 0; i < SDL_NumJoysticks(); ++i )
{
SDL_Joystick* dev = SDL_JoystickOpen( i );
if ( dev )
{
Joystick* js = new Joystick( dev, i );
// only add if it has some inputs/outputs
if ( js->Inputs().size() || js->Outputs().size() )
devices.push_back( js );
else
delete js;
}
}
}
}
Joystick::Joystick( SDL_Joystick* const joystick, const unsigned int index ) : m_joystick(joystick), m_index(index)
{
// get buttons
for ( int i = 0; i < SDL_JoystickNumButtons( m_joystick ); ++i )
{
inputs.push_back( new Button( i ) );
}
// get hats
for ( int i = 0; i < SDL_JoystickNumHats( m_joystick ); ++i )
{
// each hat gets 4 input instances associated with it, (up down left right)
for ( unsigned int d = 0; d < 4; ++d )
inputs.push_back( new Hat( i, d ) );
}
// get axes
for ( int i = 0; i < SDL_JoystickNumAxes( m_joystick ); ++i )
{
// each axis gets a negative and a positive input instance associated with it
inputs.push_back( new Axis( i, -32768 ) );
inputs.push_back( new Axis( i, 32767 ) );
}
#ifdef USE_SDL_HAPTIC
// try to get supported ff effects
m_haptic = SDL_HapticOpenFromJoystick( m_joystick );
if ( m_haptic )
{
//SDL_HapticSetGain( m_haptic, 1000 );
//SDL_HapticSetAutocenter( m_haptic, 0 );
const unsigned int supported_effects = SDL_HapticQuery( m_haptic );
// constant effect
if ( supported_effects & SDL_HAPTIC_CONSTANT )
{
outputs.push_back( new ConstantEffect( m_state_out.size() ) );
m_state_out.push_back( EffectIDState() );
}
// ramp effect
if ( supported_effects & SDL_HAPTIC_RAMP )
{
outputs.push_back( new RampEffect( m_state_out.size() ) );
m_state_out.push_back( EffectIDState() );
}
}
#endif
}
Joystick::~Joystick()
{
#ifdef USE_SDL_HAPTIC
if ( m_haptic )
{
// stop/destroy all effects
SDL_HapticStopAll( m_haptic );
std::vector<EffectIDState>::iterator i = m_state_out.begin(),
e = m_state_out.end();
for ( ; i!=e; ++i )
if ( i->id != -1 )
SDL_HapticDestroyEffect( m_haptic, i->id );
// close haptic first
SDL_HapticClose( m_haptic );
}
#endif
// close joystick
SDL_JoystickClose( m_joystick );
}
#ifdef USE_SDL_HAPTIC
std::string Joystick::ConstantEffect::GetName() const
{
return "Constant";
}
std::string Joystick::RampEffect::GetName() const
{
return "Ramp";
}
void Joystick::ConstantEffect::SetState( const ControlState state, Joystick::EffectIDState* const effect )
{
if ( state )
{
effect->effect.type = SDL_HAPTIC_CONSTANT;
effect->effect.constant.length = SDL_HAPTIC_INFINITY;
}
else
effect->effect.type = 0;
Sint16 old = effect->effect.constant.level;
effect->effect.constant.level = state * 0x7FFF;
if ( old != effect->effect.constant.level )
effect->changed = true;
}
void Joystick::RampEffect::SetState( const ControlState state, Joystick::EffectIDState* const effect )
{
if ( state )
{
effect->effect.type = SDL_HAPTIC_RAMP;
effect->effect.ramp.length = SDL_HAPTIC_INFINITY;
}
else
effect->effect.type = 0;
Sint16 old = effect->effect.ramp.start;
effect->effect.ramp.start = state * 0x7FFF;
if ( old != effect->effect.ramp.start )
effect->changed = true;
}
#endif
ControlState Joystick::GetInputState(const ControllerInterface::Device::Input* input)
{
return ((Input*)input)->GetState( m_joystick );
}
void Joystick::SetOutputState(const ControllerInterface::Device::Output* output, const ControlState state)
{
#ifdef USE_SDL_HAPTIC
((Output*)output)->SetState( state, &m_state_out[ ((Output*)output)->m_index ] );
#endif
}
bool Joystick::UpdateInput()
{
// each joystick is doin this, o well
SDL_JoystickUpdate();
return true;
}
bool Joystick::UpdateOutput()
{
#ifdef USE_SDL_HAPTIC
std::vector<EffectIDState>::iterator i = m_state_out.begin(),
e = m_state_out.end();
for ( ; i!=e; ++i )
if ( i->changed ) // if SetState was called on this output
{
if ( -1 == i->id ) // effect isn't currently uploaded
{
if ( i->effect.type ) // if outputstate is >0 this would be true
if ( (i->id = SDL_HapticNewEffect( m_haptic, &i->effect )) > -1 ) // upload the effect
SDL_HapticRunEffect( m_haptic, i->id, 1 ); // run the effect
}
else // effect is already uploaded
{
if ( i->effect.type ) // if ouputstate >0
SDL_HapticUpdateEffect( m_haptic, i->id, &i->effect ); // update the effect
else
{
SDL_HapticStopEffect( m_haptic, i->id ); // else, stop and remove the effect
SDL_HapticDestroyEffect( m_haptic, i->id );
i->id = -1; // mark it as not uploaded
}
}
i->changed = false;
}
#endif
return true;
}
std::string Joystick::GetName() const
{
return SDL_JoystickName( m_index );
}
std::string Joystick::GetSource() const
{
return "SDL";
}
int Joystick::GetId() const
{
return m_index;
}
std::string Joystick::Button::GetName() const
{
std::ostringstream ss;
ss << "Button " << m_index;
return ss.str();
}
std::string Joystick::Axis::GetName() const
{
std::ostringstream ss;
ss << "Axis " << m_index << ( m_range>0 ? '+' : '-' );
return ss.str();
}
std::string Joystick::Hat::GetName() const
{
std::ostringstream ss;
ss << "Hat " << m_index << ' ' << "NESW"[m_direction];
return ss.str();
}
ControlState Joystick::Button::GetState( SDL_Joystick* const js ) const
{
return SDL_JoystickGetButton( js, m_index );
}
ControlState Joystick::Axis::GetState( SDL_Joystick* const js ) const
{
return std::max( 0.0f, ControlState(SDL_JoystickGetAxis( js, m_index )) / m_range );
}
ControlState Joystick::Hat::GetState( SDL_Joystick* const js ) const
{
return (SDL_JoystickGetHat( js, m_index ) & ( 1 << m_direction )) > 0;
}
}
}
#endif
@@ -0,0 +1,159 @@
#ifndef _CIFACE_SDL_H_
#define _CIFACE_SDL_H_
#include "../ControllerInterface.h"
#ifdef _WIN32
#include <SDL.h>
#else
#include <SDL/SDL.h>
#endif
#if SDL_VERSION_ATLEAST(1, 3, 0)
#define USE_SDL_HAPTIC
#endif
#ifdef USE_SDL_HAPTIC
#define SDL_INIT_FLAGS SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC
#ifdef _WIN32
#include <SDL_haptic.h>
#else
#include <SDL/SDL_haptic.h>
#endif
#else
#define SDL_INIT_FLAGS SDL_INIT_JOYSTICK
#endif
namespace ciface
{
namespace SDL
{
void Init( std::vector<ControllerInterface::Device*>& devices );
class Joystick : public ControllerInterface::Device
{
friend class ControllerInterface;
friend class ControllerInterface::ControlReference;
protected:
#ifdef USE_SDL_HAPTIC
class EffectIDState
{
friend class Joystick;
protected:
EffectIDState() : id(-1), changed(false) { memset( &effect, 0, sizeof(effect)); }
protected:
SDL_HapticEffect effect;
int id;
bool changed;
};
#endif
class Input : public ControllerInterface::Device::Input
{
friend class Joystick;
protected:
Input( const unsigned int index ) : m_index(index) {}
virtual ControlState GetState( SDL_Joystick* const js ) const = 0;
const unsigned int m_index;
};
#ifdef USE_SDL_HAPTIC
class Output : public ControllerInterface::Device::Output
{
friend class Joystick;
protected:
Output( const size_t index ) : m_index(index) {}
virtual void SetState( const ControlState state, EffectIDState* const effect ) = 0;
const size_t m_index;
};
#endif
class Button : public Input
{
friend class Joystick;
public:
std::string GetName() const;
protected:
Button( const unsigned int index ) : Input(index) {}
ControlState GetState( SDL_Joystick* const js ) const;
};
class Axis : public Input
{
friend class Joystick;
public:
std::string GetName() const;
protected:
Axis( const unsigned int index, const Sint16 range ) : Input(index), m_range(range) {}
ControlState GetState( SDL_Joystick* const js ) const;
private:
const Sint16 m_range;
};
class Hat : public Input
{
friend class Joystick;
public:
std::string GetName() const;
protected:
Hat( const unsigned int index, const unsigned int direction ) : Input(index), m_direction(direction) {}
ControlState GetState( SDL_Joystick* const js ) const;
private:
const unsigned int m_direction;
};
#ifdef USE_SDL_HAPTIC
class ConstantEffect : public Output
{
friend class Joystick;
public:
std::string GetName() const;
protected:
ConstantEffect( const size_t index ) : Output(index) {}
void SetState( const ControlState state, EffectIDState* const effect );
};
class RampEffect : public Output
{
friend class Joystick;
public:
std::string GetName() const;
protected:
RampEffect( const size_t index ) : Output(index) {}
void SetState( const ControlState state, EffectIDState* const effect );
};
#endif
bool UpdateInput();
bool UpdateOutput();
ControlState GetInputState( const ControllerInterface::Device::Input* const input );
void SetOutputState( const ControllerInterface::Device::Output* const output, const ControlState state );
public:
Joystick( SDL_Joystick* const joystick, const unsigned int index );
~Joystick();
std::string GetName() const;
int GetId() const;
std::string GetSource() const;
private:
SDL_Joystick* const m_joystick;
const unsigned int m_index;
#ifdef USE_SDL_HAPTIC
std::vector<EffectIDState> m_state_out;
SDL_Haptic* m_haptic;
#endif
};
}
}
#endif
@@ -0,0 +1,214 @@
#include "../ControllerInterface.h"
#ifdef CIFACE_USE_XINPUT
#include "XInput.h"
namespace ciface
{
namespace XInput
{
struct
{
const char* const name;
const WORD bitmask;
} named_buttons[] =
{
{ "Button A", XINPUT_GAMEPAD_A },
{ "Button B", XINPUT_GAMEPAD_B },
{ "Button X", XINPUT_GAMEPAD_X },
{ "Button Y", XINPUT_GAMEPAD_Y },
{ "Pad N", XINPUT_GAMEPAD_DPAD_UP },
{ "Pad S", XINPUT_GAMEPAD_DPAD_DOWN },
{ "Pad W", XINPUT_GAMEPAD_DPAD_LEFT },
{ "Pad E", XINPUT_GAMEPAD_DPAD_RIGHT },
{ "Start", XINPUT_GAMEPAD_START },
{ "Back", XINPUT_GAMEPAD_BACK },
{ "Shoulder L", XINPUT_GAMEPAD_LEFT_SHOULDER },
{ "Shoulder R", XINPUT_GAMEPAD_RIGHT_SHOULDER },
{ "Thumb L", XINPUT_GAMEPAD_LEFT_THUMB },
{ "Thumb R", XINPUT_GAMEPAD_RIGHT_THUMB }
};
const char* named_triggers[] =
{
"Trigger L",
"Trigger R"
};
const char* named_axes[] =
{
"Left X",
"Left Y",
"Right X",
"Right Y"
};
const char* named_motors[] =
{
"Motor L",
"Motor R"
};
void Init( std::vector<ControllerInterface::Device*>& devices )
{
XINPUT_CAPABILITIES caps;
for ( int i = 0; i < 4; ++i )
if ( ERROR_SUCCESS == XInputGetCapabilities( i, 0, &caps ) )
devices.push_back( new Device( &caps, i ) );
}
Device::Device( const XINPUT_CAPABILITIES* const caps, const unsigned int index )
: m_index(index), m_subtype(caps->SubType)
{
ZeroMemory( &m_state_out, sizeof(m_state_out) );
// XInputGetCaps seems to always claim all capabilities are supported
// but i will leave all this stuff in, incase m$ fixes xinput up a bit
// get supported buttons
for ( int i = 0; i < sizeof(named_buttons)/sizeof(*named_buttons); ++i )
if ( named_buttons[i].bitmask & caps->Gamepad.wButtons )
inputs.push_back( new Button( /*xinput_named_buttons[i].bitmask, */i ) );
// get supported triggers
for ( int i = 0; i < sizeof(named_triggers)/sizeof(*named_triggers); ++i )
{
//BYTE val = (&caps->Gamepad.bLeftTrigger)[i]; // should be max value / msdn lies
if ( (&caps->Gamepad.bLeftTrigger)[i] )
inputs.push_back( new Trigger( i, 255 ) );
}
// get supported axes
for ( int i = 0; i < sizeof(named_axes)/sizeof(*named_axes); ++i )
{
//SHORT val = (&caps->Gamepad.sThumbLX)[i]; // xinput doesnt give the range / msdn is lier
if ( (&caps->Gamepad.sThumbLX)[i] )
{
// each axis gets a negative and a positive input instance associated with it
inputs.push_back( new Axis( i, -32768 ) );
inputs.push_back( new Axis( i, 32767 ) );
}
}
// get supported motors
for ( int i = 0; i < sizeof(named_motors)/sizeof(*named_motors); ++i )
{
//WORD val = (&caps->Vibration.wLeftMotorSpeed)[i]; // should be max value / nope, more lies
if ( (&caps->Vibration.wLeftMotorSpeed)[i] )
outputs.push_back( new Motor(i, 65535 ) );
}
ClearInputState();
}
void Device::ClearInputState()
{
ZeroMemory( &m_state_in, sizeof(m_state_in) );
}
std::string Device::GetName() const
{
// why aren't these defined
// subtype doesn't seem to work, i tested with 2 diff arcade sticks, both were shown as gamepad
// ill leave it in anyway, maybe m$ will fix it
switch ( m_subtype )
{
case XINPUT_DEVSUBTYPE_GAMEPAD : return "Gamepad"; break;
case 0x02 /*XINPUT_DEVSUBTYPE_WHEEL*/ : return "Wheel"; break;
case 0x03 /*XINPUT_DEVSUBTYPE_ARCADE_STICK*/ : return "Arcade Stick"; break;
case 0x04 /*XINPUT_DEVSUBTYPE_FLIGHT_STICK*/ : return "Flight Stick"; break;
case 0x05 /*XINPUT_DEVSUBTYPE_DANCE_PAD*/ : return "Dance Pad"; break;
case 0x06 /*XINPUT_DEVSUBTYPE_GUITAR*/ : return "Guitar"; break;
case 0x08 /*XINPUT_DEVSUBTYPE_DRUM_KIT*/ : return "Drum Kit"; break;
default : return "Device"; break;
}
}
int Device::GetId() const
{
return m_index;
}
std::string Device::GetSource() const
{
return "XInput";
}
// update i/o
bool Device::UpdateInput()
{
return ( ERROR_SUCCESS == XInputGetState( m_index, &m_state_in ) );
}
bool Device::UpdateOutput()
{
return ( ERROR_SUCCESS == XInputSetState( m_index, &m_state_out ) );
}
// GET name/source/id
std::string Device::Button::GetName() const
{
return named_buttons[m_index].name;
}
std::string Device::Axis::GetName() const
{
return std::string(named_axes[m_index]) + ( m_range>0 ? '+' : '-' );
}
std::string Device::Trigger::GetName() const
{
return named_triggers[m_index];
}
std::string Device::Motor::GetName() const
{
return named_motors[m_index];
}
// get/set control state
ControlState Device::GetInputState( const ControllerInterface::Device::Input* const input )
{
return ((Input*)input)->GetState( &m_state_in.Gamepad );
}
void Device::SetOutputState( const ControllerInterface::Device::Output* const output, const ControlState state )
{
return ((Output*)output)->SetState( state, &m_state_out );
}
// GET / SET STATES
ControlState Device::Button::GetState( const XINPUT_GAMEPAD* const gamepad )
{
return (gamepad->wButtons & named_buttons[m_index].bitmask) > 0;
}
ControlState Device::Trigger::GetState( const XINPUT_GAMEPAD* const gamepad )
{
return ControlState((&gamepad->bLeftTrigger)[m_index]) / m_range;
}
ControlState Device::Axis::GetState( const XINPUT_GAMEPAD* const gamepad )
{
return std::max( 0.0f, ControlState((&gamepad->sThumbLX)[m_index]) / m_range );
}
void Device::Motor::SetState( const ControlState state, XINPUT_VIBRATION* const vibration )
{
(&vibration->wLeftMotorSpeed)[m_index] = (WORD)(state * m_range);
}
}
}
#endif
@@ -0,0 +1,116 @@
#ifndef _CIFACE_XINPUT_H_
#define _CIFACE_XINPUT_H_
#include "../ControllerInterface.h"
#define NOMINMAX
#include <Windows.h>
#include <XInput.h>
namespace ciface
{
namespace XInput
{
void Init( std::vector<ControllerInterface::Device*>& devices );
class Device : public ControllerInterface::Device
{
friend class ControllerInterface;
friend class ControllerInterface::ControlReference;
protected:
class Input : public ControllerInterface::Device::Input
{
friend class Device;
protected:
virtual ControlState GetState( const XINPUT_GAMEPAD* const gamepad ) = 0;
};
class Output : public ControllerInterface::Device::Output
{
friend class Device;
protected:
virtual void SetState( const ControlState state, XINPUT_VIBRATION* const vibration ) = 0;
};
class Button : public Input
{
friend class Device;
public:
std::string GetName() const;
protected:
Button( const unsigned int index ) : m_index(index) {}
ControlState GetState( const XINPUT_GAMEPAD* const gamepad );
private:
const unsigned int m_index;
};
class Axis : public Input
{
friend class Device;
public:
std::string GetName() const;
protected:
Axis( const unsigned int index, const SHORT range ) : m_index(index), m_range(range) {}
ControlState GetState( const XINPUT_GAMEPAD* const gamepad );
private:
const unsigned int m_index;
const SHORT m_range;
};
class Trigger : public Input
{
friend class Device;
public:
std::string GetName() const;
protected:
Trigger( const unsigned int index, const BYTE range ) : m_index(index), m_range(range) {}
ControlState GetState( const XINPUT_GAMEPAD* const gamepad );
private:
const unsigned int m_index;
const BYTE m_range;
};
class Motor : public Output
{
friend class Device;
public:
std::string GetName() const;
protected:
Motor( const unsigned int index, const WORD range ) : m_index(index), m_range(range) {}
void SetState( const ControlState state, XINPUT_VIBRATION* const vibration );
private:
const unsigned int m_index;
const WORD m_range;
};
bool UpdateInput();
bool UpdateOutput();
ControlState GetInputState( const ControllerInterface::Device::Input* const input );
void SetOutputState( const ControllerInterface::Device::Output* const input, const ControlState state );
void ClearInputState();
public:
Device( const XINPUT_CAPABILITIES* const capabilities, const unsigned int index );
std::string GetName() const;
int GetId() const;
std::string GetSource() const;
private:
const unsigned int m_index;
XINPUT_STATE m_state_in;
XINPUT_VIBRATION m_state_out;
const unsigned int m_subtype;
};
}
}
#endif
@@ -0,0 +1,108 @@
#include "Xlib.h"
namespace ciface
{
namespace Xlib
{
void Init(std::vector<ControllerInterface::Device*>& devices, void* const hwnd)
{
// mouse will be added to this, Keyboard class will be turned into KeyboardMouse
// single device for combined keyboard/mouse, this will allow combinations like shift+click more easily
devices.push_back(new Keyboard((Display*)hwnd));
}
Keyboard::Keyboard(Display* display) : m_display(display)
{
memset(&m_state, 0, sizeof(m_state));
int min_keycode, max_keycode;
XDisplayKeycodes(m_display, &min_keycode, &max_keycode);
for (int i = min_keycode; i <= max_keycode; ++i)
{
Key *temp_key = new Key(m_display, i);
if (temp_key->m_keyname.length())
inputs.push_back(temp_key);
else
delete temp_key;
}
}
Keyboard::~Keyboard()
{
}
ControlState Keyboard::GetInputState(const ControllerInterface::Device::Input* const input)
{
return ((Input*)input)->GetState(&m_state);
}
void Keyboard::SetOutputState(const ControllerInterface::Device::Output* const output, const ControlState state)
{
}
bool Keyboard::UpdateInput()
{
XQueryKeymap(m_display, m_state.keyboard);
// mouse stuff in here too
return true;
}
bool Keyboard::UpdateOutput()
{
return true;
}
std::string Keyboard::GetName() const
{
return "Keyboard";
//return "Keyboard Mouse"; // change to this later
}
std::string Keyboard::GetSource() const
{
return "Xlib";
}
int Keyboard::GetId() const
{
return 0;
}
Keyboard::Key::Key(Display* const display, KeyCode keycode)
: m_display(display), m_keycode(keycode)
{
int i = 0;
KeySym keysym = 0;
do
{
keysym = XKeycodeToKeysym(m_display, keycode, i);
i++;
}
while (keysym == NoSymbol && i < 8);
if (keysym == NoSymbol)
m_keyname = std::string();
else
m_keyname = std::string(XKeysymToString(keysym));
}
ControlState Keyboard::Key::GetState(const State* const state)
{
return (state->keyboard[m_keycode/8] & (1 << (m_keycode%8))) != 0;
}
std::string Keyboard::Key::GetName() const
{
return m_keyname;
}
}
}
@@ -0,0 +1,76 @@
#ifndef _CIFACE_XLIB_H_
#define _CIFACE_XLIB_H_
#include "../ControllerInterface.h"
#include <X11/Xlib.h>
namespace ciface
{
namespace Xlib
{
void Init(std::vector<ControllerInterface::Device*>& devices, void* const hwnd);
class Keyboard : public ControllerInterface::Device
{
friend class ControllerInterface;
friend class ControllerInterface::ControlReference;
protected:
struct State
{
char keyboard[32];
// mouse crap will go here
};
class Input : public ControllerInterface::Device::Input
{
friend class Keyboard;
protected:
virtual ControlState GetState(const State* const state) = 0;
};
class Key : public Input
{
friend class Keyboard;
public:
std::string GetName() const;
protected:
Key(Display* const display, KeyCode keycode);
ControlState GetState(const State* const state);
private:
Display* const m_display;
const KeyCode m_keycode;
std::string m_keyname;
};
bool UpdateInput();
bool UpdateOutput();
ControlState GetInputState(const ControllerInterface::Device::Input* const input);
void SetOutputState(const ControllerInterface::Device::Output* const output, const ControlState state);
public:
Keyboard(Display* display);
~Keyboard();
std::string GetName() const;
std::string GetSource() const;
int GetId() const;
private:
Display* m_display;
State m_state;
};
}
}
#endif
@@ -0,0 +1,378 @@
#include <math.h>
#include "Common.h"
#include "pluginspecs_pad.h"
#include "ControllerInterface/ControllerInterface.h"
#if defined(HAVE_WX) && HAVE_WX
#include "ConfigDiag.h"
#endif
#include "Config.h"
#if defined(HAVE_X11) && HAVE_X11
#include <X11/Xlib.h>
#endif
#define PLUGIN_VERSION 0x0100
#ifdef DEBUGFAST
#define PLUGIN_FULL_NAME "Dolphin GCPad New (DebugFast)"
#else
#ifdef _DEBUG
#define PLUGIN_FULL_NAME "Dolphin GCPad New (Debug)"
#else
#define PLUGIN_FULL_NAME "Dolphin GCPad New"
#endif
#endif
#ifdef _WIN32
class wxDLLApp : public wxApp
{
bool OnInit()
{
return true;
};
};
IMPLEMENT_APP_NO_MAIN(wxDLLApp)
WXDLLIMPEXP_BASE void wxSetInstance(HINSTANCE hInst);
#endif
// copied from GCPad
SPADInitialize *g_PADInitialize = NULL;
// Check if Dolphin is in focus
// ----------------
bool IsFocus()
{
#ifdef _WIN32
HWND RenderingWindow = (g_PADInitialize) ? g_PADInitialize->hWnd : NULL;
HWND Parent = GetParent(RenderingWindow);
HWND TopLevel = GetParent(Parent);
if (GetForegroundWindow() == TopLevel || GetForegroundWindow() == RenderingWindow)
return true;
else
return false;
#elif defined HAVE_X11 && HAVE_X11
Display* GCdisplay = (Display*)g_PADInitialize->hWnd;
Window GLWin = *(Window *)g_PADInitialize->pXWindow;
bool bFocus = False;
#if defined(HAVE_GTK2) && HAVE_GTK2 && defined(wxGTK)
bFocus = (wxPanel *)g_PADInitialize->pPanel == wxWindow::FindFocus();
#endif
Window FocusWin;
int Revert;
XGetInputFocus(GCdisplay, &FocusWin, &Revert);
return (GLWin == FocusWin || bFocus);
#else
return true;
#endif
}
// copied from GCPad
HINSTANCE g_hInstance;
// copied from GCPad
#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
// /
// the plugin
Plugin g_plugin;
#ifdef _WIN32
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved )
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
wxSetInstance(hinstDLL);
wxInitialize();
break;
case DLL_PROCESS_DETACH:
wxUninitialize();
break;
default:
break;
}
g_hInstance = hinstDLL;
return TRUE;
}
#endif
// if plugin isn't initialized, init and load config
void InitPlugin( void* const hwnd )
{
//g_plugin.controls_crit.Enter(); // enter
//g_plugin.interface_crit.Enter();
if ( false == g_plugin.controller_interface.IsInit() )
{
// load the saved controller config
g_plugin.LoadConfig();
// needed for Xlib and exclusive dinput
g_plugin.controller_interface.SetHwnd( hwnd );
g_plugin.controller_interface.Init();
// update control refs
std::vector<ControllerEmu*>::const_iterator i = g_plugin.controllers.begin(),
e = g_plugin.controllers.end();
for ( ; i!=e; ++i )
(*i)->UpdateReferences( g_plugin.controller_interface );
}
//g_plugin.interface_crit.Leave();
//g_plugin.controls_crit.Leave(); // leave
}
// I N T E R F A C E
// __________________________________________________________________________________________________
// Function:
// Purpose:
// input:
// output:
//
void PAD_GetStatus(u8 _numPAD, SPADStatus* _pPADStatus)
{
// why not, i guess
if ( NULL == _pPADStatus )
return;
memset( _pPADStatus, 0, sizeof(*_pPADStatus) );
_pPADStatus->err = PAD_ERR_NONE;
// wtf is this?
_pPADStatus->button |= PAD_USE_ORIGIN;
// try lock
if ( false == g_plugin.controls_crit.TryEnter() )
{
// if gui has lock (messing with controls), skip this input cycle
// center axes and return
memset( &_pPADStatus->stickX, 0x80, 4 );
return;
}
// if we are on the next input cycle, update output and input
// if we can get a lock
static int _last_numPAD = 4;
if ( _numPAD <= _last_numPAD && g_plugin.interface_crit.TryEnter() )
{
g_plugin.controller_interface.UpdateOutput();
g_plugin.controller_interface.UpdateInput();
g_plugin.interface_crit.Leave();
}
_last_numPAD = _numPAD;
// if we want background input or have focus
if ( g_plugin.controllers[_numPAD]->options[0].settings[0]->value || IsFocus() )
{
// get input
((GCPad*)g_plugin.controllers[ _numPAD ])->GetInput( _pPADStatus );
}
else
{
// center sticks
memset( &_pPADStatus->stickX, 0x80, 4 );
// stop rumble
((GCPad*)g_plugin.controllers[ _numPAD ])->SetOutput( false );
}
// leave
g_plugin.controls_crit.Leave();
}
// __________________________________________________________________________________________________
// Function: Send keyboard input to the plugin
// Purpose:
// input: The key and if it's pressed or released
// output: None
//
void PAD_Input(u16 _Key, u8 _UpDown)
{
// nofin
}
// __________________________________________________________________________________________________
// Function: PAD_Rumble
// Purpose: Pad rumble!
// input: PAD number, Command type (Stop=0, Rumble=1, Stop Hard=2) and strength of Rumble
// output: none
//
void PAD_Rumble(u8 _numPAD, unsigned int _uType, unsigned int _uStrength)
{
// enter
if ( g_plugin.controls_crit.TryEnter() )
{
// only on/off rumble, if we have focus or background input on
if ( g_plugin.controllers[_numPAD]->options[0].settings[0]->value || IsFocus() )
((GCPad*)g_plugin.controllers[ _numPAD ])->SetOutput( 1 == _uType && _uStrength > 2 );
// leave
g_plugin.controls_crit.Leave();
}
}
// GLOBAL I N T E R F A C E
// Function: GetDllInfo
// Purpose: This function allows the emulator to gather information
// about the DLL by filling in the PluginInfo structure.
// input: A pointer to a PLUGIN_INFO structure that needs to be
// filled by the function. (see def above)
// output: none
//
void GetDllInfo(PLUGIN_INFO* _pPluginInfo)
{
// don't feel like messing around with all those strcpy functions and warnings
//char *s1 = CIFACE_PLUGIN_FULL_NAME, *s2 = _pPluginInfo->Name;
//while ( *s2++ = *s1++ );
memcpy( _pPluginInfo->Name, PLUGIN_FULL_NAME, sizeof(PLUGIN_FULL_NAME) );
_pPluginInfo->Type = PLUGIN_TYPE_PAD;
_pPluginInfo->Version = PLUGIN_VERSION;
}
// ___________________________________________________________________________
// Function: DllConfig
// Purpose: This function is optional function that is provided
// to allow the user to configure the DLL
// input: A handle to the window that calls this function
// output: none
//
void DllConfig(HWND _hParent)
{
bool was_init = false;
#if defined(HAVE_X11) && HAVE_X11
Display *dpy = NULL;
#endif
if ( g_plugin.controller_interface.IsInit() ) // hack for showing dialog when game isnt running
was_init = true;
else
{
#if defined(HAVE_X11) && HAVE_X11
dpy = XOpenDisplay(0);
InitPlugin(dpy);
#else
InitPlugin(_hParent);
#endif
}
// copied from GCPad
#if defined(HAVE_WX) && HAVE_WX
wxWindow *frame = GetParentedWxWindow(_hParent);
ConfigDialog* m_ConfigFrame = new ConfigDialog( frame, g_plugin, PLUGIN_FULL_NAME, was_init );
#ifdef _WIN32
frame->Disable();
m_ConfigFrame->ShowModal();
frame->Enable();
#else
m_ConfigFrame->ShowModal();
#endif
#ifdef _WIN32
wxMilliSleep( 50 ); // hooray for hacks
frame->SetFocus();
frame->SetHWND(NULL);
#endif
m_ConfigFrame->Destroy();
m_ConfigFrame = NULL;
frame->Destroy();
#endif
// /
if ( !was_init ) // hack for showing dialog when game isnt running
{
#if defined(HAVE_X11) && HAVE_X11
XCloseDisplay(dpy);
#endif
g_plugin.controller_interface.DeInit();
}
}
// ___________________________________________________________________________
// Function: DllDebugger
// Purpose: Open the debugger
// input: a handle to the window that calls this function
// output: none
//
void DllDebugger(HWND _hParent, bool Show)
{
// wut?
}
// ___________________________________________________________________________
// Function: DllSetGlobals
// Purpose: Set the pointer for globals variables
// input: a pointer to the global struct
// output: none
//
void SetDllGlobals(PLUGIN_GLOBALS* _pPluginGlobals)
{
// wut?
}
// ___________________________________________________________________________
// Function: Initialize
// Purpose: Initialize the plugin
// input: Init
// output: none
//
void Initialize(void *init)
{
g_PADInitialize = (SPADInitialize*)init;
if ( false == g_plugin.controller_interface.IsInit() )
InitPlugin( ((SPADInitialize*)init)->hWnd );
}
// ___________________________________________________________________________
// Function: Shutdown
// Purpose: This function is called when the emulator is shutting down
// a game allowing the dll to de-initialise.
// input: none
// output: none
//
void Shutdown(void)
{
//plugin.controls_crit.Enter(); // enter
if ( g_plugin.controller_interface.IsInit() )
g_plugin.controller_interface.DeInit();
//plugin.controls_crit.Leave(); // leave
}
// ___________________________________________________________________________
// Function: DoState
// Purpose: Saves/load state
// input/output: ptr
// input: mode
//
void DoState(unsigned char **ptr, int mode)
{
// prolly won't need this
}
// ___________________________________________________________________________
// Function: EmuStateChange
// Purpose: Notifies the plugin of a change in emulation state
// input: newState
// output: none
//
void EmuStateChange(PLUGIN_EMUSTATE newState)
{
// maybe use this later
}
@@ -0,0 +1,142 @@
#include "IniFile.h"
//
// TrimChars
//
// trim whitespace, or any, chars from both ends
//
template <typename S>
std::string TrimChars( const std::string& str, const S space )
{
const size_t start = str.find_first_not_of( space );
if ( str.npos == start )
return "";
return str.substr( start, str.find_last_not_of( space ) - start + 1 );
}
//
// IniSection :: Set
//
// set key's value if it doesn't match the default
// otherwise remove the key from the section if it exists
//
void IniSection::Set( const std::string& key, const std::string& val, const std::string& def )
{
if ( val != def )
operator[](key) = val;
else
{
iterator f = find(key);
if ( f != end() )
erase( f );
}
}
//
// IniSection :: Get
//
// return a key's value if it exists
// otherwise return the default
//
std::string IniSection::Get( const std::string& key, const std::string& def )
{
const const_iterator f = find(key);
if ( f != end() )
if ( false == f->second.empty() )
return f->second;
return def;
}
//
// IniFile :: Save
//
// save a file
//
void IniFile::Save( std::ostream& file )
{
const_iterator i = begin(),
e = end();
for ( ; i != e; ++i )
{
// skip a line at new sections
file << "\n[" << i->first << "]\n";
Section::const_iterator si = i->second.begin(),
se = i->second.end();
for ( ; si != se; ++si )
file << si->first << " = " << si->second << '\n';
}
}
//
// IniFile :: Load
//
// load a file
//
void IniFile::Load( std::istream& file )
{
const char* const space = "\t\r ";
std::string line;
// start off with an empty section
Section* section = &(*this)[""];
while ( std::getline( file, line ).good() ) // read a line
{
line = TrimChars(line,space);
if ( line.size() )
{
switch ( line[0] )
{
// comment
case '#' :
case ';' :
break;
// section
case '[' :
// kinda odd trimming
section = &(*this)[ TrimChars(line,"][\t\r ") ];
break;
// key/value
default :
{
std::istringstream ss(line);
std::string key; std::getline( ss, key, '=' );
std::string val; std::getline( ss, val );
(*section)[ TrimChars(key,space) ] = TrimChars(val,space);
break;
}
}
}
}
Clean();
}
//
// IniFile :: Clean
//
// remove empty key/values and sections
// after trying to access ini sections/values, they are automatically allocated
// this deletes the empty stuff
//
void IniFile::Clean()
{
iterator i = begin(),
e = end();
for ( ; i != e; )
{
Section::iterator si = i->second.begin(),
se = i->second.end();
for ( ; si != se; )
{
if ( si->second.empty() )
i->second.erase( si++ );
else
++si;
}
if ( i->second.empty() )
erase( i++ );
else
++i;
}
}
@@ -0,0 +1,61 @@
#ifndef _INIFILE_H_
#define _INIFILE_H_
#include <fstream>
#include <map>
#include <string>
#include <sstream>
//
// IniFile
//
class IniSection : public std::map< std::string, std::string >
{
public:
void Set( const std::string& key, const std::string& val, const std::string& def = "" );
std::string Get( const std::string& key, const std::string& def = "" );
template <typename V, typename D>
void Set( const std::string& key, const V& val, const D& def = 0 )
{
if ( val != def )
{
std::ostringstream ss;
ss << long(val);
operator[](key) = ss.str();
}
else
{
iterator f = find(key);
if ( f != end() )
erase( f );
}
}
template <typename V>
V Get( const std::string& key, const V& def = 0 )
{
const const_iterator f = find(key);
if ( f != end() )
if ( false == f->second.empty() )
{
std::istringstream ss(f->second);
int val;
ss >> val;
return V(val);
}
return def;
}
};
class IniFile : public std::map< std::string, IniSection >
{
public:
typedef IniSection Section;
void Clean();
void Save( std::ostream& file );
void Load( std::istream& file );
};
#endif
@@ -0,0 +1,36 @@
# -*- python -*-
Import('env')
import sys
name = "Plugin_GCPadNew"
padenv = env.Clone()
files = [
'Config.cpp',
'ControllerEmu.cpp',
'ControllerEmu/GCPad/GCPad.cpp',
'GCPadNew.cpp',
'ControllerInterface/ControllerInterface.cpp',
'IniFile.cpp'
]
if padenv['HAVE_SDL']:
files += [ 'ControllerInterface/SDL/SDL.cpp' ]
if sys.platform == 'linux2':
files += [ 'ControllerInterface/Xlib/Xlib.cpp' ]
if padenv['HAVE_WX']:
files += [
'ConfigDiag.cpp',
'ConfigDiagBitmaps.cpp',
]
padenv.Append(
LIBS = [ 'inputcommon', 'common' ],
)
if sys.platform == 'darwin':
padenv['FRAMEWORKS'] = ['CoreFoundation', 'System', 'Cocoa' ]
padenv.SharedLibrary(env['plugin_dir']+name, files)
+1 -1
View File
@@ -173,7 +173,7 @@ unsigned int Callback_PeekMessages()
void UpdateFPSDisplay(const char *text)
{
char temp[512];
sprintf_s(temp, 512, "SVN R%i: DX9: %s", SVN_REV, text);
sprintf_s(temp, 512, "%s: DX9: %s", SVN_REV_STR, text);
SetWindowTextA(EmuWindow::GetWnd(), temp);
}
+269 -166
View File
@@ -113,58 +113,95 @@ unsigned int Callback_PeekMessages()
void UpdateFPSDisplay(const char *text)
{
char temp[512];
sprintf(temp, "SVN R%s: GL: %s", SVN_REV_STR, text);
sprintf(temp, "%s: GL: %s", SVN_REV_STR, text);
OpenGL_SetWindowText(temp);
}
#if defined(HAVE_X11) && HAVE_X11
THREAD_RETURN XEventThread(void *pArg);
void X11_EWMH_Fullscreen(int action)
{
_assert_(action == _NET_WM_STATE_REMOVE || action == _NET_WM_STATE_ADD
|| action == _NET_WM_STATE_TOGGLE);
// Init X event structure for _NET_WM_STATE_FULLSCREEN client message
XEvent event;
event.xclient.type = ClientMessage;
event.xclient.message_type = XInternAtom(GLWin.dpy, "_NET_WM_STATE", False);
event.xclient.window = GLWin.win;
event.xclient.format = 32;
event.xclient.data.l[0] = action;
event.xclient.data.l[1] = XInternAtom(GLWin.dpy, "_NET_WM_STATE_FULLSCREEN", False);
// Send the event
if (!XSendEvent(GLWin.dpy, DefaultRootWindow(GLWin.dpy), False,
SubstructureRedirectMask | SubstructureNotifyMask, &event))
ERROR_LOG(VIDEO, "Failed to switch fullscreen/windowed mode.\n");
}
void CreateXWindow (void)
{
Atom wmProtocols[3];
int width, height;
Window parent;
if (GLWin.fs)
{
#if defined(HAVE_XRANDR) && HAVE_XRANDR
if (GLWin.fullSize >= 0)
XRRSetScreenConfig(GLWin.dpy, GLWin.screenConfig, RootWindow(GLWin.dpy, GLWin.screen),
GLWin.fullSize, GLWin.screenRotation, CurrentTime);
#if defined(HAVE_GTK2) && HAVE_GTK2 && defined(wxGTK)
wxMutexGuiEnter();
#endif
GLWin.attr.override_redirect = True;
width = GLWin.fullWidth;
height = GLWin.fullHeight;
#if defined(HAVE_XRANDR) && HAVE_XRANDR
if (GLWin.fs && !GLWin.renderToMain)
XRRSetScreenConfig(GLWin.dpy, GLWin.screenConfig, RootWindow(GLWin.dpy, GLWin.screen),
GLWin.fullSize, GLWin.screenRotation, CurrentTime);
#endif
#if defined(HAVE_GTK2) && HAVE_GTK2 && defined(wxGTK)
if (GLWin.renderToMain)
{
GLWin.panel->GetSize((int *)&GLWin.width, (int *)&GLWin.height);
GLWin.panel->GetPosition(&GLWin.x, &GLWin.y);
parent = GDK_WINDOW_XID(GTK_WIDGET(GLWin.panel->GetHandle())->window);
GLWin.panel->SetFocus();
}
else
#endif
{
GLWin.attr.override_redirect = False;
width = GLWin.winWidth;
height = GLWin.winHeight;
GLWin.x = 0;
GLWin.y = 0;
GLWin.width = GLWin.winWidth;
GLWin.height = GLWin.winHeight;
parent = RootWindow(GLWin.dpy, GLWin.vi->screen);
}
// Control window size and picture scaling
s_backbuffer_width = width;
s_backbuffer_height = height;
s_backbuffer_width = GLWin.width;
s_backbuffer_height = GLWin.height;
// create the window
GLWin.attr.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask |
StructureNotifyMask | ResizeRedirectMask;
GLWin.win = XCreateWindow(GLWin.dpy, RootWindow(GLWin.dpy, GLWin.vi->screen),
0, 0, width, height, 0, GLWin.vi->depth, InputOutput, GLWin.vi->visual,
CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect, &GLWin.attr);
GLWin.win = XCreateWindow(GLWin.dpy, parent,
GLWin.x, GLWin.y, GLWin.width, GLWin.height, 0, GLWin.vi->depth, InputOutput, GLWin.vi->visual,
CWBorderPixel | CWBackPixel | CWColormap | CWEventMask, &GLWin.attr);
wmProtocols[0] = XInternAtom(GLWin.dpy, "WM_DELETE_WINDOW", True);
wmProtocols[1] = XInternAtom(GLWin.dpy, "WM_TAKE_FOCUS", True);
wmProtocols[2] = XInternAtom(GLWin.dpy, "TOGGLE_FULLSCREEN", False);
wmProtocols[1] = XInternAtom(GLWin.dpy, "_NET_WM_STATE", False);
wmProtocols[2] = XInternAtom(GLWin.dpy, "_NET_WM_STATE_FULLSCREEN", False);
XSetWMProtocols(GLWin.dpy, GLWin.win, wmProtocols, 3);
XSetStandardProperties(GLWin.dpy, GLWin.win, "GPU", "GPU", None, NULL, 0, NULL);
XMapRaised(GLWin.dpy, GLWin.win);
if (GLWin.fs)
{
XGrabKeyboard(GLWin.dpy, GLWin.win, True, GrabModeAsync, GrabModeAsync, CurrentTime);
XGrabPointer(GLWin.dpy, GLWin.win, True, NULL,
GrabModeAsync, GrabModeAsync, GLWin.win, None, CurrentTime);
XSetInputFocus(GLWin.dpy, GLWin.win, RevertToPointerRoot, CurrentTime);
}
XSync(GLWin.dpy, True);
#if defined(HAVE_GTK2) && HAVE_GTK2 && defined(wxGTK)
wxMutexGuiLeave();
#endif
if (g_Config.bHideCursor)
{
// make a blank cursor
Pixmap Blank;
XColor DummyColor;
char ZeroData[1] = {0};
Blank = XCreateBitmapFromData (GLWin.dpy, GLWin.win, ZeroData, 1, 1);
GLWin.blankCursor = XCreatePixmapCursor(GLWin.dpy, Blank, Blank, &DummyColor, &DummyColor, 0, 0);
XFreePixmap (GLWin.dpy, Blank);
}
GLWin.xEventThread = new Common::Thread(XEventThread, NULL);
}
void DestroyXWindow(void)
@@ -179,25 +216,180 @@ void DestroyXWindow(void)
/* switch back to original desktop resolution if we were in fullscreen */
if( GLWin.fs )
{
XUngrabKeyboard (GLWin.dpy, CurrentTime);
XUngrabPointer (GLWin.dpy, CurrentTime);
#if defined(HAVE_XRANDR) && HAVE_XRANDR
if (GLWin.fullSize >= 0)
XRRSetScreenConfig(GLWin.dpy, GLWin.screenConfig, RootWindow(GLWin.dpy, GLWin.screen),
GLWin.deskSize, GLWin.screenRotation, CurrentTime);
XRRSetScreenConfig(GLWin.dpy, GLWin.screenConfig, RootWindow(GLWin.dpy, GLWin.screen),
GLWin.deskSize, GLWin.screenRotation, CurrentTime);
#if defined(HAVE_GTK2) && HAVE_GTK2 && defined(wxGTK)
if (!GLWin.renderToMain)
#endif
X11_EWMH_Fullscreen(_NET_WM_STATE_REMOVE);
#endif
}
XUndefineCursor(GLWin.dpy, GLWin.win);
XUnmapWindow(GLWin.dpy, GLWin.win);
XSync(GLWin.dpy, True);
GLWin.win = 0;
}
void ToggleFullscreenMode (void)
{
DestroyXWindow();
GLWin.fs = !GLWin.fs;
CreateXWindow();
OpenGL_MakeCurrent();
#if defined(HAVE_XRANDR) && HAVE_XRANDR
if (GLWin.fs)
XRRSetScreenConfig(GLWin.dpy, GLWin.screenConfig, RootWindow(GLWin.dpy, GLWin.screen),
GLWin.fullSize, GLWin.screenRotation, CurrentTime);
else
XRRSetScreenConfig(GLWin.dpy, GLWin.screenConfig, RootWindow(GLWin.dpy, GLWin.screen),
GLWin.deskSize, GLWin.screenRotation, CurrentTime);
#endif
#if defined(HAVE_GTK2) && HAVE_GTK2 && defined(wxGTK)
if (!GLWin.renderToMain)
#endif
{
X11_EWMH_Fullscreen(_NET_WM_STATE_TOGGLE);
XRaiseWindow(GLWin.dpy, GLWin.win);
XSetInputFocus(GLWin.dpy, GLWin.win, RevertToPointerRoot, CurrentTime);
}
XSync(GLWin.dpy, False);
}
THREAD_RETURN XEventThread(void *pArg)
{
bool bPaused = False;
while (GLWin.win)
{
XEvent event;
KeySym key;
for (int num_events = XPending(GLWin.dpy); num_events > 0; num_events--) {
XNextEvent(GLWin.dpy, &event);
switch(event.type) {
case KeyPress:
key = XLookupKeysym((XKeyEvent*)&event, 0);
switch (key)
{
case XK_F1: case XK_F2: case XK_F3: case XK_F4: case XK_F5: case XK_F6:
case XK_F7: case XK_F8: case XK_F9: case XK_F11: case XK_F12:
g_VideoInitialize.pKeyPress(key - 0xff4e,
event.xkey.state & ShiftMask,
event.xkey.state & ControlMask);
break;
case XK_Escape:
if (GLWin.fs && !bPaused)
{
printf("toggling fullscreen\n");
ToggleFullscreenMode();
}
g_VideoInitialize.pKeyPress(0x1c, False, False);
break;
case XK_Return:
if (event.xkey.state & Mod1Mask)
ToggleFullscreenMode();
break;
case XK_3:
OSDChoice = 1;
// Toggle native resolution
if (!(g_Config.bNativeResolution || g_Config.b2xResolution))
g_Config.bNativeResolution = true;
else if (g_Config.bNativeResolution && Renderer::AllowCustom())
{ g_Config.bNativeResolution = false; if (Renderer::Allow2x()) {g_Config.b2xResolution = true;} }
else if (Renderer::AllowCustom())
g_Config.b2xResolution = false;
break;
case XK_4:
OSDChoice = 2;
// Toggle aspect ratio
g_Config.iAspectRatio = (g_Config.iAspectRatio + 1) & 3;
break;
case XK_5:
OSDChoice = 3;
// Toggle EFB copy
if (g_Config.bEFBCopyDisable || g_Config.bCopyEFBToTexture)
{
g_Config.bEFBCopyDisable = !g_Config.bEFBCopyDisable;
g_Config.bCopyEFBToTexture = false;
}
else
{
g_Config.bCopyEFBToTexture = !g_Config.bCopyEFBToTexture;
}
break;
case XK_6:
OSDChoice = 4;
g_Config.bDisableFog = !g_Config.bDisableFog;
break;
case XK_7:
OSDChoice = 5;
g_Config.bDisableLighting = !g_Config.bDisableLighting;
break;
default:
break;
}
break;
case FocusIn:
if (g_Config.bHideCursor && !bPaused && !GLWin.renderToMain)
XDefineCursor(GLWin.dpy, GLWin.win, GLWin.blankCursor);
break;
case FocusOut:
if (g_Config.bHideCursor && !bPaused && !GLWin.renderToMain)
XUndefineCursor(GLWin.dpy, GLWin.win);
break;
case ConfigureNotify:
Window winDummy;
unsigned int borderDummy;
XGetGeometry(GLWin.dpy, GLWin.win, &winDummy, &GLWin.x, &GLWin.y,
&GLWin.width, &GLWin.height, &borderDummy, &GLWin.depth);
s_backbuffer_width = GLWin.width;
s_backbuffer_height = GLWin.height;
// Save windowed mode size for return from fullscreen
if (!GLWin.fs)
{
GLWin.winWidth = GLWin.width;
GLWin.winHeight = GLWin.height;
}
break;
case ClientMessage:
if ((ulong) event.xclient.data.l[0] == XInternAtom(GLWin.dpy, "WM_DELETE_WINDOW", False))
g_VideoInitialize.pKeyPress(0x1b, False, False);
if ((ulong) event.xclient.data.l[0] == XInternAtom(GLWin.dpy, "TOGGLE_FULLSCREEN", False))
ToggleFullscreenMode();
if (g_Config.bHideCursor &&
(ulong) event.xclient.data.l[0] == XInternAtom(GLWin.dpy, "PAUSE", False))
{
bPaused = True;
XUndefineCursor(GLWin.dpy, GLWin.win);
}
if (g_Config.bHideCursor &&
(ulong) event.xclient.data.l[0] == XInternAtom(GLWin.dpy, "RESUME", False))
{
bPaused = False;
XDefineCursor(GLWin.dpy, GLWin.win, GLWin.blankCursor);
}
#if defined(HAVE_GTK2) && HAVE_GTK2 && defined(wxGTK)
if (GLWin.renderToMain &&
(ulong) event.xclient.data.l[0] == XInternAtom(GLWin.dpy, "RESIZE", False))
{
GLWin.panel->GetSize((int *)&GLWin.width, (int *)&GLWin.height);
GLWin.panel->GetPosition(&GLWin.x, &GLWin.y);
XMoveResizeWindow(GLWin.dpy, GLWin.win, GLWin.x, GLWin.y, GLWin.width, GLWin.height);
}
if (GLWin.renderToMain &&
(ulong) event.xclient.data.l[0] == XInternAtom(GLWin.dpy, "FOCUSIN", False))
{
GLWin.panel->SetFocus();
if (g_Config.bHideCursor)
XDefineCursor(GLWin.dpy, GLWin.win, GLWin.blankCursor);
}
if (GLWin.renderToMain && g_Config.bHideCursor &&
(ulong) event.xclient.data.l[0] == XInternAtom(GLWin.dpy, "FOCUSOUT", False))
XUndefineCursor(GLWin.dpy, GLWin.win);
#endif
break;
default:
break;
}
}
Common::SleepCurrentThread(20);
}
return 0;
}
#endif
@@ -352,7 +544,6 @@ bool OpenGL_Create(SVideoInitialize &_VideoInitialize, int _iwidth, int _iheight
// --------------------------------------
#elif defined(HAVE_X11) && HAVE_X11
Colormap cmap;
int glxMajorVersion, glxMinorVersion;
int vidModeMajorVersion, vidModeMinorVersion;
@@ -375,11 +566,20 @@ bool OpenGL_Create(SVideoInitialize &_VideoInitialize, int _iwidth, int _iheight
GLWin.dpy = XOpenDisplay(0);
g_VideoInitialize.pWindowHandle = (HWND)GLWin.dpy;
#if defined(HAVE_GTK2) && HAVE_GTK2 && defined(wxGTK)
GLWin.panel = (wxPanel *)g_VideoInitialize.pPanel;
#endif
g_VideoInitialize.pWindowHandle = (Display *)GLWin.dpy;
GLWin.screen = DefaultScreen(GLWin.dpy);
// Fullscreen option.
GLWin.fs = g_Config.bFullscreen; //Set to setting in Options
// Render to main option.
#if defined(HAVE_GTK2) && HAVE_GTK2 && defined(wxGTK)
GLWin.renderToMain = g_Config.RenderToMainframe;
#else
GLWin.renderToMain = False;
#endif
/* get an appropriate visual */
GLWin.vi = glXChooseVisual(GLWin.dpy, GLWin.screen, attrListDbl);
@@ -402,9 +602,12 @@ bool OpenGL_Create(SVideoInitialize &_VideoInitialize, int _iwidth, int _iheight
PanicAlert("Couldn't Create GLX context.Quit");
exit(0); // TODO: Don't bring down entire Emu
}
// Create a color map.
cmap = XCreateColormap(GLWin.dpy, RootWindow(GLWin.dpy, GLWin.vi->screen), GLWin.vi->visual, AllocNone);
GLWin.attr.colormap = cmap;
// Create a color map and set the event masks
GLWin.attr.colormap = XCreateColormap(GLWin.dpy,
RootWindow(GLWin.dpy, GLWin.vi->screen), GLWin.vi->visual, AllocNone);
GLWin.attr.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask |
StructureNotifyMask | ResizeRedirectMask;
GLWin.attr.background_pixel = BlackPixel(GLWin.dpy, GLWin.screen);
GLWin.attr.border_pixel = 0;
XkbSetDetectableAutoRepeat(GLWin.dpy, True, NULL);
@@ -459,19 +662,14 @@ bool OpenGL_Create(SVideoInitialize &_VideoInitialize, int _iwidth, int _iheight
GLWin.fullHeight = DisplayHeight(GLWin.dpy, GLWin.screen);
#endif
#if defined(HAVE_GTK2) && HAVE_GTK2 && defined(wxGTK)
if (GLWin.renderToMain)
g_VideoInitialize.pKeyPress(0, False, False);
#endif
CreateXWindow();
g_VideoInitialize.pXWindow = (Window *) &GLWin.win;
if (g_Config.bHideCursor)
{
// make a blank cursor
Pixmap Blank;
XColor DummyColor;
char ZeroData[1] = {0};
Blank = XCreateBitmapFromData (GLWin.dpy, GLWin.win, ZeroData, 1, 1);
GLWin.blankCursor = XCreatePixmapCursor(GLWin.dpy, Blank, Blank, &DummyColor, &DummyColor, 0, 0);
XFreePixmap (GLWin.dpy, Blank);
}
#endif
return true;
}
@@ -501,6 +699,19 @@ bool OpenGL_MakeCurrent()
ERROR_LOG(VIDEO, "no Direct Rendering possible!");
}
if (GLWin.fs)
{
#if defined(HAVE_GTK2) && HAVE_GTK2 && defined(wxGTK)
if (GLWin.renderToMain)
{
GLWin.fs = False;
g_VideoInitialize.pKeyPress(0x1d, False, False);
}
else
#endif
X11_EWMH_Fullscreen(_NET_WM_STATE_ADD);
}
// Hide the cursor now
if (g_Config.bHideCursor)
XDefineCursor (GLWin.dpy, GLWin.win, GLWin.blankCursor);
@@ -557,118 +768,6 @@ void OpenGL_Update()
s_backbuffer_height = height;
#elif defined(HAVE_X11) && HAVE_X11
// We just check all of our events here
XEvent event;
KeySym key;
int num_events;
for (num_events = XPending(GLWin.dpy);num_events > 0;num_events--) {
XNextEvent(GLWin.dpy, &event);
switch(event.type) {
case KeyPress:
key = XLookupKeysym((XKeyEvent*)&event, 0);
switch (key)
{
case XK_F4:
if(event.xkey.state & Mod1Mask)
{
g_VideoInitialize.pKeyPress(0x1b, False, False);
break;
}
case XK_F1: case XK_F2: case XK_F3: case XK_F5:
case XK_F6: case XK_F7: case XK_F8: case XK_F9:
g_VideoInitialize.pKeyPress(key - 0xff4e,
event.xkey.state & ShiftMask,
event.xkey.state & ControlMask);
break;
case XK_Escape:
if (GLWin.fs)
{
ToggleFullscreenMode();
XEvent mapevent;
do {
XMaskEvent(GLWin.dpy, StructureNotifyMask, &mapevent);
} while ( (mapevent.type != MapNotify) || (mapevent.xmap.event != GLWin.win) );
}
g_VideoInitialize.pKeyPress(0x1c, False, False);
break;
case XK_Return:
if (event.xkey.state & Mod1Mask)
ToggleFullscreenMode();
break;
case XK_3:
OSDChoice = 1;
// Toggle native resolution
if (!(g_Config.bNativeResolution || g_Config.b2xResolution))
g_Config.bNativeResolution = true;
else if (g_Config.bNativeResolution && Renderer::AllowCustom())
{ g_Config.bNativeResolution = false; if (Renderer::Allow2x()) {g_Config.b2xResolution = true;} }
else if (Renderer::AllowCustom())
g_Config.b2xResolution = false;
break;
case XK_4:
OSDChoice = 2;
// Toggle aspect ratio
g_Config.iAspectRatio = (g_Config.iAspectRatio + 1) & 3;
break;
case XK_5:
OSDChoice = 3;
// Toggle EFB copy
if (g_Config.bEFBCopyDisable || g_Config.bCopyEFBToTexture)
{
g_Config.bEFBCopyDisable = !g_Config.bEFBCopyDisable;
g_Config.bCopyEFBToTexture = false;
}
else
{
g_Config.bCopyEFBToTexture = !g_Config.bCopyEFBToTexture;
}
break;
case XK_6:
OSDChoice = 4;
g_Config.bDisableFog = !g_Config.bDisableFog;
break;
case XK_7:
OSDChoice = 5;
g_Config.bDisableLighting = !g_Config.bDisableLighting;
break;
default:
break;
}
case FocusIn:
if (g_Config.bHideCursor)
XDefineCursor(GLWin.dpy, GLWin.win, GLWin.blankCursor);
break;
case FocusOut:
if (g_Config.bHideCursor && !GLWin.fs)
XUndefineCursor(GLWin.dpy, GLWin.win);
break;
case ConfigureNotify:
Window winDummy;
unsigned int borderDummy;
XGetGeometry(GLWin.dpy, GLWin.win, &winDummy, &GLWin.x, &GLWin.y,
&GLWin.width, &GLWin.height, &borderDummy, &GLWin.depth);
s_backbuffer_width = GLWin.width;
s_backbuffer_height = GLWin.height;
// Save windowed mode size for return from fullscreen
if (!GLWin.fs)
{
GLWin.winWidth = GLWin.width;
GLWin.winHeight = GLWin.height;
}
break;
case ClientMessage:
if ((ulong) event.xclient.data.l[0] == XInternAtom(GLWin.dpy, "WM_DELETE_WINDOW", False))
g_VideoInitialize.pKeyPress(0x1b, False, False);
if ((ulong) event.xclient.data.l[0] == XInternAtom(GLWin.dpy, "TOGGLE_FULLSCREEN", False))
ToggleFullscreenMode();
return;
break;
default:
break;
}
}
return;
#endif
}
@@ -708,6 +807,9 @@ void OpenGL_Shutdown()
}
#elif defined(HAVE_X11) && HAVE_X11
DestroyXWindow();
if (GLWin.xEventThread)
GLWin.xEventThread->WaitForDeath();
GLWin.xEventThread = NULL;
#if defined(HAVE_XRANDR) && HAVE_XRANDR
if (GLWin.fullSize >= 0)
XRRFreeScreenConfigInfo(GLWin.screenConfig);
@@ -717,6 +819,7 @@ void OpenGL_Shutdown()
if (GLWin.ctx)
{
glXDestroyContext(GLWin.dpy, GLWin.ctx);
XFreeColormap(GLWin.dpy, GLWin.attr.colormap);
XCloseDisplay(GLWin.dpy);
GLWin.ctx = NULL;
}
+26 -11
View File
@@ -31,19 +31,38 @@
#include <GLew/gl.h>
#include <GLew/glext.h>
#else // linux basic definitions
#else // linux and apple basic definitions
#if defined(USE_WX) && USE_WX
#include <GL/glew.h>
#include "wx/wx.h"
#include "wx/glcanvas.h"
#elif defined(HAVE_X11) && HAVE_X11
#define I_NEED_OS2_H // HAXXOR
#include <GL/glxew.h>
#include <X11/XKBlib.h>
#if defined(HAVE_GTK2) && HAVE_GTK2 // Needed for render to main
#include <gtk/gtk.h>
#include <gdk/gdkx.h>
#include <wx/wx.h>
#endif
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>
#include "Thread.h"
#if defined(HAVE_XRANDR) && HAVE_XRANDR
#include <X11/extensions/Xrandr.h>
#endif // XRANDR
// EWMH state actions, see
// http://freedesktop.org/wiki/Specifications/wm-spec?action=show&redirect=Standards%2Fwm-spec
#define _NET_WM_STATE_REMOVE 0 /* remove/unset property */
#define _NET_WM_STATE_ADD 1 /* add/set property */
#define _NET_WM_STATE_TOGGLE 2 /* toggle property */
#elif defined(USE_SDL) && USE_SDL
#include <GL/glew.h>
#include <SDL.h>
#elif defined(HAVE_COCOA) && HAVE_COCOA
#include <GL/glew.h>
#include "cocoaGL.h"
@@ -65,15 +84,6 @@
#endif
#ifndef _WIN32
#if defined(HAVE_X11) && HAVE_X11
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>
#if defined(HAVE_XRANDR) && HAVE_XRANDR
#include <X11/extensions/Xrandr.h>
#endif // XRANDR
#endif // X11
#include <sys/stat.h>
#include <sys/types.h>
@@ -85,6 +95,9 @@ typedef struct {
NSOpenGLContext *cocoaCtx;
#elif defined(HAVE_X11) && HAVE_X11
Window win;
#if defined(HAVE_GTK2) && HAVE_GTK2 && defined(wxGTK)
wxPanel *panel;
#endif
Display *dpy;
XVisualInfo *vi;
GLXContext ctx;
@@ -94,6 +107,8 @@ typedef struct {
Bool doubleBuffered;
int fullWidth, fullHeight;
int winWidth, winHeight;
Common::Thread *xEventThread;
Bool renderToMain;
#if defined(HAVE_XRANDR) && HAVE_XRANDR
XRRScreenConfiguration *screenConfig;
Rotation screenRotation;
@@ -833,8 +833,10 @@ void GFXConfigDialogOGL::UpdateGUI()
m_AutoScale->Enable(!g_Config.bUseXFB);
// These options are for the separate rendering window
#if !defined(HAVE_GTK2) || !HAVE_GTK2 || !defined(wxGTK)
m_Fullscreen->Enable(!g_Config.RenderToMainframe);
if (g_Config.RenderToMainframe) m_Fullscreen->SetValue(false);
#endif
// Resolution settings
//disable native/2x choice when real xfb is on. native simply looks best, as ector noted above.
@@ -842,7 +844,11 @@ void GFXConfigDialogOGL::UpdateGUI()
m_NativeResolution->Enable(!g_Config.bUseXFB);
m_2xResolution->Enable(!g_Config.bUseXFB && (!g_Config.bRunning || Renderer::Allow2x()));
m_WindowResolutionCB->Enable(!g_Config.bRunning);
#if defined(HAVE_GTK2) && HAVE_GTK2 && defined(wxGTK)
m_WindowFSResolutionCB->Enable(!g_Config.bRunning);
#else
m_WindowFSResolutionCB->Enable(!g_Config.bRunning && !g_Config.RenderToMainframe);
#endif
// Disable the Copy to options when EFBCopy is disabled
m_Radio_CopyEFBToRAM->Enable(!(g_Config.bEFBCopyDisable));
@@ -31,7 +31,7 @@ compileFlags = [
linkFlags = [
]
libs = [
'videocommon', 'soil', 'common'
'videocommon', 'SOIL', 'common'
]
gfxenv = env.Clone()
@@ -105,6 +105,10 @@ gfxenv['HAVE_XRANDR'] = gfxenv['HAVE_X11'] and conf.CheckPKG('xrandr')
conf.Define('HAVE_XRANDR', gfxenv['HAVE_XRANDR'])
# check for libgtk2.0
gfxenv['HAVE_GTK2'] = gfxenv['HAVE_WX'] and conf.CheckPKG('gtk+-2.0')
conf.Define('HAVE_GTK2', gfxenv['HAVE_GTK2'])
conf.Finish()
# Sanity check
+8 -6
View File
@@ -208,12 +208,18 @@ void Win32AddResolutions()
}
#elif defined(HAVE_X11) && HAVE_X11 && defined(HAVE_XRANDR) && HAVE_XRANDR
void X11AddResolutions() {
GLWin.dpy = XOpenDisplay(0);
// Don't modify GLWin.dpy here.
// If the emulator is running that is bad.
Display *dpy;
int screen;
dpy = XOpenDisplay(0);
screen = DefaultScreen(dpy);
//Get all full screen resos for the config dialog
XRRScreenSize *sizes = NULL;
int modeNum = 0;
sizes = XRRSizes(GLWin.dpy, GLWin.screen, &modeNum);
sizes = XRRSizes(dpy, screen, &modeNum);
XCloseDisplay(dpy);
if (modeNum > 0 && sizes != NULL)
{
for (int i = 0; i < modeNum; i++)
@@ -349,10 +355,6 @@ void Initialize(void *init)
}
void DoState(unsigned char **ptr, int mode) {
#ifndef _WIN32
// WHY is this here??
OpenGL_MakeCurrent();
#endif
// Clear all caches that touch RAM
TextureMngr::Invalidate(false);
VertexLoaderManager::MarkAllDirty();
@@ -117,7 +117,7 @@ unsigned int Callback_PeekMessages()
void UpdateFPSDisplay(const char *text)
{
char temp[512];
sprintf(temp, "SVN R%s: SW: %s", SVN_REV_STR, text);
sprintf(temp, "%s: SW: %s", SVN_REV_STR, text);
OpenGL_SetWindowText(temp);
}
// =========================
@@ -42,7 +42,7 @@ compileFlags = [
linkFlags = [
]
libs = [
'videocommon', 'soil', 'common'
'videocommon', 'SOIL', 'common'
]
gfxenv = env.Clone()
@@ -222,10 +222,7 @@ void WiimotePadConfigDialog::DoGetButtons(int _GetId)
DEBUG_LOG(WIIMOTE, "Timer Stopped for Pad:%i _GetId:%i",
WiiMoteEmu::WiiMapping[m_Page].ID, _GetId);
m_ButtonMappingTimer->Stop();
GetButtonWaitingTimer = 0;
GetButtonWaitingID = 0;
ClickedButton = NULL;
EndGetButtons();
}
// If we got a bad button
@@ -241,6 +238,17 @@ void WiimotePadConfigDialog::DoGetButtons(int _GetId)
}
}
void WiimotePadConfigDialog::EndGetButtons(void)
{
wxTheApp->Disconnect(wxID_ANY, wxEVT_KEY_DOWN, // Keyboard
wxKeyEventHandler(WiimotePadConfigDialog::OnKeyDown),
(wxObject*)0, this);
m_ButtonMappingTimer->Stop();
GetButtonWaitingTimer = 0;
GetButtonWaitingID = 0;
ClickedButton = NULL;
}
// Convert the 0x8000 range values to BoxW and BoxH for the plot
void WiimotePadConfigDialog::Convert2Box(int &x)
{
@@ -135,10 +135,6 @@ WiimotePadConfigDialog::WiimotePadConfigDialog(wxWindow *parent, wxWindowID id,
m_Notebook->ChangeSelection(m_Page);
// Set control values
UpdateGUI();
wxTheApp->Connect(wxID_ANY, wxEVT_KEY_DOWN, // Keyboard
wxKeyEventHandler(WiimotePadConfigDialog::OnKeyDown),
(wxObject*)0, this);
}
WiimotePadConfigDialog::~WiimotePadConfigDialog()
@@ -247,10 +243,7 @@ void WiimotePadConfigDialog::OnKeyDown(wxKeyEvent& event)
SaveButtonMapping(ClickedButton->GetId(), XKey);
#endif
}
m_ButtonMappingTimer->Stop();
GetButtonWaitingTimer = 0;
GetButtonWaitingID = 0;
ClickedButton = NULL;
EndGetButtons();
}
}
@@ -264,6 +257,10 @@ void WiimotePadConfigDialog::OnButtonClick(wxCommandEvent& event)
if (m_ButtonMappingTimer->IsRunning()) return;
wxTheApp->Connect(wxID_ANY, wxEVT_KEY_DOWN, // Keyboard
wxKeyEventHandler(WiimotePadConfigDialog::OnKeyDown),
(wxObject*)0, this);
// Create the button object
ClickedButton = (wxButton *)event.GetEventObject();
// Save old label so we can revert back
@@ -867,6 +864,7 @@ void WiimotePadConfigDialog::CreatePadGUIControls()
{
m_statictext_GH3[x][i] = new wxStaticText(m_Controller[i], wxID_ANY, gh3Text[x]);
m_Button_GH3[x][i] = new wxButton(m_Controller[i], x, wxEmptyString, wxDefaultPosition, wxSize(BtW, BtH));
m_Button_GH3[x][i]->SetFont(m_SmallFont);
m_Sizer_GH3[x][i] = new wxBoxSizer(wxHORIZONTAL);
m_Sizer_GH3[x][i]->Add(m_statictext_GH3[x][i], 0, (wxUP), 4);
m_Sizer_GH3[x][i]->Add(m_Button_GH3[x][i], 0, (wxLEFT), 2);
@@ -288,6 +288,7 @@ class WiimotePadConfigDialog : public wxDialog
wxString GetButtonText(int id);
void DoGetButtons(int id);
void EndGetButtons();
void UpdatePadInfo(wxTimerEvent& WXUNUSED(event));
void ToBlank(bool ToBlank, int Id);
void DoChangeDeadZone();
+5 -3
View File
@@ -397,12 +397,14 @@ bool IsFocus()
return false;
#elif defined HAVE_X11 && HAVE_X11
Window GLWin = *(Window *)g_WiimoteInitialize.pXWindow;
bool bFocus = False;
#if defined(HAVE_GTK2) && HAVE_GTK2 && defined(wxGTK)
bFocus = (wxPanel *)g_WiimoteInitialize.pPanel == wxWindow::FindFocus();
#endif
Window FocusWin;
int Revert;
XGetInputFocus(WMdisplay, &FocusWin, &Revert);
XWindowAttributes WinAttribs;
XGetWindowAttributes (WMdisplay, GLWin, &WinAttribs);
return (GLWin != 0 && (GLWin == FocusWin || WinAttribs.override_redirect));
return (GLWin == FocusWin || bFocus);
#else
return true;
#endif
@@ -720,6 +720,7 @@ int WiimotePairUp(void)
}
} while (BluetoothFindNextDevice(hFind, &btdi));
BluetoothFindRadioClose(hFind);
}
SLEEP(10);