Initial commit: ROW Client source code
Game client codebase including: - CharacterActionControl: Character and creature management - GlobalScript: Network, items, skills, quests, utilities - RYLClient: Main client application with GUI and event handlers - Engine: 3D rendering engine (RYLGL) - MemoryManager: Custom memory allocation - Library: Third-party dependencies (DirectX, boost, etc.) - Tools: Development utilities 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,187 @@
|
||||
# Microsoft Developer Studio Project File - Name="MultiMapper" - Package Owner=<4>
|
||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
||||
# ** DO NOT EDIT **
|
||||
|
||||
# TARGTYPE "Win32 (x86) Application" 0x0101
|
||||
|
||||
CFG=MultiMapper - Win32 Debug
|
||||
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
||||
!MESSAGE use the Export Makefile command and run
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "MultiMapper.mak".
|
||||
!MESSAGE
|
||||
!MESSAGE You can specify a configuration when running NMAKE
|
||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "MultiMapper.mak" CFG="MultiMapper - Win32 Debug"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "MultiMapper - Win32 Release Unicode" (based on "Win32 (x86) Application")
|
||||
!MESSAGE "MultiMapper - Win32 Debug Unicode" (based on "Win32 (x86) Application")
|
||||
!MESSAGE "MultiMapper - Win32 Release" (based on "Win32 (x86) Application")
|
||||
!MESSAGE "MultiMapper - Win32 Debug" (based on "Win32 (x86) Application")
|
||||
!MESSAGE
|
||||
|
||||
# Begin Project
|
||||
# PROP AllowPerConfigDependencies 0
|
||||
# PROP Scc_ProjName ""
|
||||
# PROP Scc_LocalPath ""
|
||||
CPP=cl.exe
|
||||
MTL=midl.exe
|
||||
RSC=rc.exe
|
||||
|
||||
!IF "$(CFG)" == "MultiMapper - Win32 Release Unicode"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "MultiMapper___Win32_Release_Unicode"
|
||||
# PROP BASE Intermediate_Dir "MultiMapper___Win32_Release_Unicode"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "MultiMapper___Win32_Release_Unicode"
|
||||
# PROP Intermediate_Dir "MultiMapper___Win32_Release_Unicode"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /GX /O2 /I "..\..\common\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
|
||||
# ADD CPP /nologo /W3 /GX /O2 /I "..\..\common\include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "UNICODE" /D "_UNICODE" /YX /FD /c
|
||||
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 dsound.lib dinput8.lib dxerr8.lib d3dx8dt.lib d3d8.lib d3dxof.lib dxguid.lib winmm.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /stack:0x200000,0x200000 /subsystem:windows /machine:I386
|
||||
# ADD LINK32 dsound.lib dinput8.lib dxerr8.lib d3dx8dt.lib d3d8.lib d3dxof.lib dxguid.lib shlwapi.lib winmm.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /stack:0x200000,0x200000 /subsystem:windows /machine:I386
|
||||
|
||||
!ELSEIF "$(CFG)" == "MultiMapper - Win32 Debug Unicode"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 1
|
||||
# PROP BASE Output_Dir "MultiMapper___Win32_Debug_Unicode"
|
||||
# PROP BASE Intermediate_Dir "MultiMapper___Win32_Debug_Unicode"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 1
|
||||
# PROP Output_Dir "MultiMapper___Win32_Debug_Unicode"
|
||||
# PROP Intermediate_Dir "MultiMapper___Win32_Debug_Unicode"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\common\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
|
||||
# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\common\include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "UNICODE" /D "_UNICODE" /YX /FD /GZ /c
|
||||
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||
# ADD RSC /l 0x409 /d "_DEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 dsound.lib dinput8.lib dxerr8.lib d3dx8dt.lib d3d8.lib d3dxof.lib dxguid.lib winmm.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /stack:0x200000,0x200000 /subsystem:windows /debug /machine:I386 /pdbtype:sept
|
||||
# ADD LINK32 dsound.lib dinput8.lib dxerr8.lib d3dx8dt.lib d3d8.lib d3dxof.lib dxguid.lib shlwapi.lib winmm.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /stack:0x200000,0x200000 /subsystem:windows /debug /machine:I386 /pdbtype:sept
|
||||
|
||||
!ELSEIF "$(CFG)" == "MultiMapper - Win32 Release"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "Release"
|
||||
# PROP BASE Intermediate_Dir "Release"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "Release"
|
||||
# PROP Intermediate_Dir "Release"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
|
||||
# ADD CPP /nologo /W3 /GX /O2 /I "..\..\common\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
|
||||
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 dsound.lib dinput8.lib dxerr8.lib d3dx8dt.lib d3d8.lib d3dxof.lib dxguid.lib winmm.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
|
||||
# ADD LINK32 dsound.lib dinput8.lib dxerr8.lib d3dx8dt.lib d3d8.lib d3dxof.lib dxguid.lib shlwapi.lib winmm.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /stack:0x200000,0x200000 /subsystem:windows /machine:I386
|
||||
|
||||
!ELSEIF "$(CFG)" == "MultiMapper - Win32 Debug"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 1
|
||||
# PROP BASE Output_Dir "Debug"
|
||||
# PROP BASE Intermediate_Dir "Debug"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 1
|
||||
# PROP Output_Dir "Debug"
|
||||
# PROP Intermediate_Dir "Debug"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
|
||||
# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\common\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
|
||||
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||
# ADD RSC /l 0x409 /d "_DEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 dsound.lib dinput8.lib dxerr8.lib d3dx8dt.lib d3d8.lib d3dxof.lib dxguid.lib winmm.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
|
||||
# ADD LINK32 dsound.lib dinput8.lib dxerr8.lib d3dx8dt.lib d3d8.lib d3dxof.lib dxguid.lib shlwapi.lib winmm.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /stack:0x200000,0x200000 /subsystem:windows /debug /machine:I386 /pdbtype:sept
|
||||
|
||||
!ENDIF
|
||||
|
||||
# Begin Target
|
||||
|
||||
# Name "MultiMapper - Win32 Release Unicode"
|
||||
# Name "MultiMapper - Win32 Debug Unicode"
|
||||
# Name "MultiMapper - Win32 Release"
|
||||
# Name "MultiMapper - Win32 Debug"
|
||||
# Begin Group "Source Files"
|
||||
|
||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\DirectX.ico
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\multidi.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\multidi.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\MultiMapper.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\MultiMapper.rc
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\resource.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Common"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\common\src\dxutil.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\common\include\dxutil.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# End Target
|
||||
# End Project
|
||||
@@ -0,0 +1,29 @@
|
||||
Microsoft Developer Studio Workspace File, Format Version 6.00
|
||||
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
|
||||
|
||||
###############################################################################
|
||||
|
||||
Project: "MultiMapper"=.\MultiMapper.dsp - Package Owner=<4>
|
||||
|
||||
Package=<5>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
Package=<4>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
||||
Global:
|
||||
|
||||
Package=<5>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
Package=<3>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
||||
@@ -0,0 +1,220 @@
|
||||
# Microsoft Developer Studio Generated NMAKE File, Based on MultiMapper.dsp
|
||||
!IF "$(CFG)" == ""
|
||||
CFG=MultiMapper - Win32 Debug
|
||||
!MESSAGE No configuration specified. Defaulting to MultiMapper - Win32 Debug.
|
||||
!ENDIF
|
||||
|
||||
!IF "$(CFG)" != "MultiMapper - Win32 Release" && "$(CFG)" != "MultiMapper - Win32 Debug"
|
||||
!MESSAGE Invalid configuration "$(CFG)" specified.
|
||||
!MESSAGE You can specify a configuration when running NMAKE
|
||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "MultiMapper.mak" CFG="MultiMapper - Win32 Debug"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "MultiMapper - Win32 Release" (based on "Win32 (x86) Application")
|
||||
!MESSAGE "MultiMapper - Win32 Debug" (based on "Win32 (x86) Application")
|
||||
!MESSAGE
|
||||
!ERROR An invalid configuration is specified.
|
||||
!ENDIF
|
||||
|
||||
!IF "$(OS)" == "Windows_NT"
|
||||
NULL=
|
||||
!ELSE
|
||||
NULL=nul
|
||||
!ENDIF
|
||||
|
||||
!IF "$(CFG)" == "MultiMapper - Win32 Release"
|
||||
|
||||
OUTDIR=.\Release
|
||||
INTDIR=.\Release
|
||||
# Begin Custom Macros
|
||||
OutDir=.\Release
|
||||
# End Custom Macros
|
||||
|
||||
ALL : "$(OUTDIR)\MultiMapper.exe"
|
||||
|
||||
|
||||
CLEAN :
|
||||
-@erase "$(INTDIR)\dxutil.obj"
|
||||
-@erase "$(INTDIR)\multidi.obj"
|
||||
-@erase "$(INTDIR)\MultiMapper.obj"
|
||||
-@erase "$(INTDIR)\MultiMapper.res"
|
||||
-@erase "$(INTDIR)\vc60.idb"
|
||||
-@erase "$(OUTDIR)\MultiMapper.exe"
|
||||
|
||||
"$(OUTDIR)" :
|
||||
if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
|
||||
|
||||
CPP=cl.exe
|
||||
CPP_PROJ=/nologo /ML /W3 /GX /O2 /I "..\..\common\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /Fp"$(INTDIR)\MultiMapper.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
|
||||
|
||||
.c{$(INTDIR)}.obj::
|
||||
$(CPP) @<<
|
||||
$(CPP_PROJ) $<
|
||||
<<
|
||||
|
||||
.cpp{$(INTDIR)}.obj::
|
||||
$(CPP) @<<
|
||||
$(CPP_PROJ) $<
|
||||
<<
|
||||
|
||||
.cxx{$(INTDIR)}.obj::
|
||||
$(CPP) @<<
|
||||
$(CPP_PROJ) $<
|
||||
<<
|
||||
|
||||
.c{$(INTDIR)}.sbr::
|
||||
$(CPP) @<<
|
||||
$(CPP_PROJ) $<
|
||||
<<
|
||||
|
||||
.cpp{$(INTDIR)}.sbr::
|
||||
$(CPP) @<<
|
||||
$(CPP_PROJ) $<
|
||||
<<
|
||||
|
||||
.cxx{$(INTDIR)}.sbr::
|
||||
$(CPP) @<<
|
||||
$(CPP_PROJ) $<
|
||||
<<
|
||||
|
||||
MTL=midl.exe
|
||||
MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32
|
||||
RSC=rc.exe
|
||||
RSC_PROJ=/l 0x409 /fo"$(INTDIR)\MultiMapper.res" /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
BSC32_FLAGS=/nologo /o"$(OUTDIR)\MultiMapper.bsc"
|
||||
BSC32_SBRS= \
|
||||
|
||||
LINK32=link.exe
|
||||
LINK32_FLAGS=dsound.lib dinput8.lib dxerr8.lib d3dx8dt.lib d3d8.lib d3dxof.lib dxguid.lib winmm.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /incremental:no /pdb:"$(OUTDIR)\MultiMapper.pdb" /machine:I386 /out:"$(OUTDIR)\MultiMapper.exe" /stack:0x200000,0x200000
|
||||
LINK32_OBJS= \
|
||||
"$(INTDIR)\multidi.obj" \
|
||||
"$(INTDIR)\MultiMapper.obj" \
|
||||
"$(INTDIR)\dxutil.obj" \
|
||||
"$(INTDIR)\MultiMapper.res"
|
||||
|
||||
"$(OUTDIR)\MultiMapper.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
|
||||
$(LINK32) @<<
|
||||
$(LINK32_FLAGS) $(LINK32_OBJS)
|
||||
<<
|
||||
|
||||
!ELSEIF "$(CFG)" == "MultiMapper - Win32 Debug"
|
||||
|
||||
OUTDIR=.\Debug
|
||||
INTDIR=.\Debug
|
||||
# Begin Custom Macros
|
||||
OutDir=.\Debug
|
||||
# End Custom Macros
|
||||
|
||||
ALL : "$(OUTDIR)\MultiMapper.exe"
|
||||
|
||||
|
||||
CLEAN :
|
||||
-@erase "$(INTDIR)\dxutil.obj"
|
||||
-@erase "$(INTDIR)\multidi.obj"
|
||||
-@erase "$(INTDIR)\MultiMapper.obj"
|
||||
-@erase "$(INTDIR)\MultiMapper.res"
|
||||
-@erase "$(INTDIR)\vc60.idb"
|
||||
-@erase "$(INTDIR)\vc60.pdb"
|
||||
-@erase "$(OUTDIR)\MultiMapper.exe"
|
||||
-@erase "$(OUTDIR)\MultiMapper.ilk"
|
||||
-@erase "$(OUTDIR)\MultiMapper.pdb"
|
||||
|
||||
"$(OUTDIR)" :
|
||||
if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
|
||||
|
||||
CPP=cl.exe
|
||||
CPP_PROJ=/nologo /MLd /W3 /Gm /GX /ZI /Od /I "..\..\common\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /Fp"$(INTDIR)\MultiMapper.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /GZ /c
|
||||
|
||||
.c{$(INTDIR)}.obj::
|
||||
$(CPP) @<<
|
||||
$(CPP_PROJ) $<
|
||||
<<
|
||||
|
||||
.cpp{$(INTDIR)}.obj::
|
||||
$(CPP) @<<
|
||||
$(CPP_PROJ) $<
|
||||
<<
|
||||
|
||||
.cxx{$(INTDIR)}.obj::
|
||||
$(CPP) @<<
|
||||
$(CPP_PROJ) $<
|
||||
<<
|
||||
|
||||
.c{$(INTDIR)}.sbr::
|
||||
$(CPP) @<<
|
||||
$(CPP_PROJ) $<
|
||||
<<
|
||||
|
||||
.cpp{$(INTDIR)}.sbr::
|
||||
$(CPP) @<<
|
||||
$(CPP_PROJ) $<
|
||||
<<
|
||||
|
||||
.cxx{$(INTDIR)}.sbr::
|
||||
$(CPP) @<<
|
||||
$(CPP_PROJ) $<
|
||||
<<
|
||||
|
||||
MTL=midl.exe
|
||||
MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32
|
||||
RSC=rc.exe
|
||||
RSC_PROJ=/l 0x409 /fo"$(INTDIR)\MultiMapper.res" /d "_DEBUG"
|
||||
BSC32=bscmake.exe
|
||||
BSC32_FLAGS=/nologo /o"$(OUTDIR)\MultiMapper.bsc"
|
||||
BSC32_SBRS= \
|
||||
|
||||
LINK32=link.exe
|
||||
LINK32_FLAGS=dsound.lib dinput8.lib dxerr8.lib d3dx8dt.lib d3d8.lib d3dxof.lib dxguid.lib winmm.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /incremental:yes /pdb:"$(OUTDIR)\MultiMapper.pdb" /debug /machine:I386 /out:"$(OUTDIR)\MultiMapper.exe" /pdbtype:sept /stack:0x200000,0x200000
|
||||
LINK32_OBJS= \
|
||||
"$(INTDIR)\multidi.obj" \
|
||||
"$(INTDIR)\MultiMapper.obj" \
|
||||
"$(INTDIR)\dxutil.obj" \
|
||||
"$(INTDIR)\MultiMapper.res"
|
||||
|
||||
"$(OUTDIR)\MultiMapper.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
|
||||
$(LINK32) @<<
|
||||
$(LINK32_FLAGS) $(LINK32_OBJS)
|
||||
<<
|
||||
|
||||
!ENDIF
|
||||
|
||||
|
||||
!IF "$(NO_EXTERNAL_DEPS)" != "1"
|
||||
!IF EXISTS("MultiMapper.dep")
|
||||
!INCLUDE "MultiMapper.dep"
|
||||
!ELSE
|
||||
!MESSAGE Warning: cannot find "MultiMapper.dep"
|
||||
!ENDIF
|
||||
!ENDIF
|
||||
|
||||
|
||||
!IF "$(CFG)" == "MultiMapper - Win32 Release" || "$(CFG)" == "MultiMapper - Win32 Debug"
|
||||
SOURCE=.\multidi.cpp
|
||||
|
||||
"$(INTDIR)\multidi.obj" : $(SOURCE) "$(INTDIR)"
|
||||
|
||||
|
||||
SOURCE=.\MultiMapper.cpp
|
||||
|
||||
"$(INTDIR)\MultiMapper.obj" : $(SOURCE) "$(INTDIR)"
|
||||
|
||||
|
||||
SOURCE=.\MultiMapper.rc
|
||||
|
||||
"$(INTDIR)\MultiMapper.res" : $(SOURCE) "$(INTDIR)"
|
||||
$(RSC) $(RSC_PROJ) $(SOURCE)
|
||||
|
||||
|
||||
SOURCE=..\..\common\src\dxutil.cpp
|
||||
|
||||
"$(INTDIR)\dxutil.obj" : $(SOURCE) "$(INTDIR)"
|
||||
$(CPP) $(CPP_PROJ) $(SOURCE)
|
||||
|
||||
|
||||
|
||||
!ENDIF
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
//Microsoft Developer Studio generated resource script.
|
||||
//
|
||||
#include "resource.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 2 resource.
|
||||
//
|
||||
#define IDC_STATIC -1
|
||||
#include <Windows.h>
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// English (U.S.) resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
|
||||
#ifdef _WIN32
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
#pragma code_page(1252)
|
||||
#endif //_WIN32
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TEXTINCLUDE
|
||||
//
|
||||
|
||||
1 TEXTINCLUDE DISCARDABLE
|
||||
BEGIN
|
||||
"resource.h\0"
|
||||
END
|
||||
|
||||
2 TEXTINCLUDE DISCARDABLE
|
||||
BEGIN
|
||||
"#define IDC_STATIC -1\r\n"
|
||||
"#include <Windows.h>\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
3 TEXTINCLUDE DISCARDABLE
|
||||
BEGIN
|
||||
"\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Icon
|
||||
//
|
||||
|
||||
// Icon with lowest ID value placed first to ensure application icon
|
||||
// remains consistent on all systems.
|
||||
IDI_MAIN ICON DISCARDABLE "DirectX.ico"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// DESIGNINFO
|
||||
//
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
GUIDELINES DESIGNINFO DISCARDABLE
|
||||
BEGIN
|
||||
IDD_MAIN, DIALOG
|
||||
BEGIN
|
||||
LEFTMARGIN, 7
|
||||
RIGHTMARGIN, 326
|
||||
TOPMARGIN, 7
|
||||
BOTTOMMARGIN, 251
|
||||
END
|
||||
END
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Dialog
|
||||
//
|
||||
|
||||
IDD_MAIN DIALOG DISCARDABLE 0, 0, 333, 260
|
||||
STYLE DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE |
|
||||
WS_CAPTION | WS_SYSMENU
|
||||
CAPTION "DirectInput MultiMapper Sample"
|
||||
FONT 8, "MS Shell Dlg"
|
||||
BEGIN
|
||||
PUSHBUTTON "E&xit",IDCANCEL,262,55,64,14
|
||||
PUSHBUTTON "Configure &Input",IDM_CONFIGINPUT,262,7,64,14
|
||||
RTEXT "Left/Right Axis:",IDC_STATIC,16,89,55,8
|
||||
RTEXT "Up/Down Axis:",IDC_STATIC,16,79,55,8
|
||||
LTEXT "Static",IDC_UD_AXIS_STATE_P1,80,79,48,8
|
||||
LTEXT "Static",IDC_LR_AXIS_STATE_P1,80,89,48,8
|
||||
RTEXT "Button State:",IDC_STATIC,16,99,55,8
|
||||
LTEXT "Static",IDC_BUTTON_STATE_P1,80,99,48,8
|
||||
LTEXT "Set the number of players, and click 'Configure Input' to view or change input settings.",
|
||||
IDC_STATIC,7,27,244,17
|
||||
GROUPBOX "Player 1",IDC_PLAYER1_GROUP,7,70,319,43
|
||||
GROUPBOX "Player 2",IDC_PLAYER2_GROUP,7,115,319,43
|
||||
RTEXT "Left/Right Axis:",IDC_TEXT2_P2,16,135,55,8
|
||||
RTEXT "Up/Down Axis:",IDC_TEXT1_P2,16,125,55,8
|
||||
LTEXT "Static",IDC_UD_AXIS_STATE_P2,80,125,48,8
|
||||
LTEXT "Static",IDC_LR_AXIS_STATE_P2,80,135,48,8
|
||||
RTEXT "Button State:",IDC_TEXT3_P2,16,145,55,8
|
||||
LTEXT "Static",IDC_BUTTON_STATE_P2,80,145,48,8
|
||||
LTEXT "Number of active players:",IDC_STATIC,7,54,81,8
|
||||
COMBOBOX IDC_NUM_PLAYERS_COMBO,91,52,30,51,CBS_DROPDOWN |
|
||||
CBS_SORT | WS_VSCROLL | WS_TABSTOP
|
||||
RTEXT "Left/Right Axis:",IDC_TEXT2_P3,16,180,55,8
|
||||
RTEXT "Up/Down Axis:",IDC_TEXT1_P3,16,170,55,8
|
||||
LTEXT "Static",IDC_UD_AXIS_STATE_P3,80,170,48,8
|
||||
LTEXT "Static",IDC_LR_AXIS_STATE_P3,80,180,48,8
|
||||
RTEXT "Button State:",IDC_TEXT3_P3,16,190,55,8
|
||||
LTEXT "Static",IDC_BUTTON_STATE_P3,80,190,48,8
|
||||
GROUPBOX "Player 3",IDC_PLAYER3_GROUP,7,160,319,43
|
||||
GROUPBOX "Player 4",IDC_PLAYER4_GROUP,7,206,319,43
|
||||
RTEXT "Left/Right Axis:",IDC_TEXT2_P4,16,225,55,8
|
||||
RTEXT "Up/Down Axis:",IDC_TEXT1_P4,16,215,55,8
|
||||
LTEXT "Static",IDC_UD_AXIS_STATE_P4,80,215,48,8
|
||||
LTEXT "Static",IDC_LR_AXIS_STATE_P4,80,225,48,8
|
||||
RTEXT "Button State:",IDC_TEXT3_P4,16,235,55,8
|
||||
LTEXT "Static",IDC_BUTTON_STATE_P4,80,235,48,8
|
||||
LTEXT "This sample shows how a game can use the DirectInput action mapper to assign input devices to players based on knowledge of a user's prefered device. ",
|
||||
IDC_STATIC,7,7,252,19
|
||||
LTEXT "Sum of movement:",IDC_STATIC,130,54,60,8
|
||||
LTEXT "Static",IDC_WORLD_STATE,191,54,65,8
|
||||
PUSHBUTTON "Reset &Ownership",IDC_RESET_OWNERSHIP,262,23,64,14
|
||||
LISTBOX IDC_DEVICE_ASSIGNED_P1,133,80,185,27,LBS_SORT |
|
||||
LBS_NOINTEGRALHEIGHT | LBS_NOSEL | WS_VSCROLL |
|
||||
WS_TABSTOP
|
||||
LISTBOX IDC_DEVICE_ASSIGNED_P2,133,125,185,27,LBS_SORT |
|
||||
LBS_NOINTEGRALHEIGHT | LBS_NOSEL | WS_VSCROLL |
|
||||
WS_TABSTOP
|
||||
LISTBOX IDC_DEVICE_ASSIGNED_P3,133,170,185,27,LBS_SORT |
|
||||
LBS_NOINTEGRALHEIGHT | LBS_NOSEL | WS_VSCROLL |
|
||||
WS_TABSTOP
|
||||
LISTBOX IDC_DEVICE_ASSIGNED_P4,133,216,185,27,LBS_SORT |
|
||||
LBS_NOINTEGRALHEIGHT | LBS_NOSEL | WS_VSCROLL |
|
||||
WS_TABSTOP
|
||||
PUSHBUTTON "Reset &Mappings",IDC_RESET_MAPPINGS,262,39,64,14
|
||||
END
|
||||
|
||||
#endif // English (U.S.) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 3 resource.
|
||||
//
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
|
||||
@@ -0,0 +1,909 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// File: MultiDI.cpp
|
||||
//
|
||||
// Desc: DirectInput framework class using semantic mapping with multiplayer
|
||||
// device ownership. Feel free to use this class as a starting point
|
||||
// for adding extra functionality.
|
||||
//
|
||||
// Copyright (C) 1995-2001 Microsoft Corporation. All Rights Reserved.
|
||||
//-----------------------------------------------------------------------------
|
||||
#define STRICT
|
||||
#define DIRECTINPUT_VERSION 0x0800
|
||||
#include <basetsd.h>
|
||||
#include <tchar.h>
|
||||
#include <stdio.h>
|
||||
#include <windows.h>
|
||||
#include <shlwapi.h> // defines SHDeleteKey
|
||||
#include <dxerr8.h>
|
||||
#include <d3d8types.h> // included to get the D3DCOLOR_RGBA macro.
|
||||
#include "MultiDI.h"
|
||||
#include "DXUtil.h"
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: CMultiplayerInputDeviceManager
|
||||
// Desc: Constructor
|
||||
// Args: strRegKey - A location in the registry where device ownership
|
||||
// information should be stored
|
||||
//-----------------------------------------------------------------------------
|
||||
CMultiplayerInputDeviceManager::CMultiplayerInputDeviceManager( TCHAR* strRegKey )
|
||||
{
|
||||
HRESULT hr = CoInitialize(NULL);
|
||||
m_bCleanupCOM = SUCCEEDED(hr);
|
||||
LONG nResult;
|
||||
|
||||
// Initialize members
|
||||
m_pDI = NULL;
|
||||
m_hWnd = NULL;
|
||||
m_pdiaf = NULL;
|
||||
m_pUsers = NULL;
|
||||
m_pDeviceList = NULL;
|
||||
m_AddDeviceCallback = NULL;
|
||||
m_AddDeviceCallbackParam = NULL;
|
||||
m_hKey = NULL;
|
||||
m_dwNumDevices = 0;
|
||||
m_dwMaxDevices = 0;
|
||||
|
||||
|
||||
// Duplicate the registry location string since we'll need this again later
|
||||
m_strKey = _tcsdup( strRegKey );
|
||||
if( m_strKey == NULL )
|
||||
return;
|
||||
|
||||
// Create a reg key to store device ownership data
|
||||
nResult = RegCreateKeyEx( HKEY_CURRENT_USER, strRegKey, 0, NULL,
|
||||
REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
|
||||
&m_hKey, NULL );
|
||||
if(nResult != ERROR_SUCCESS)
|
||||
m_hKey = NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: ~CMultiplayerInputDeviceManager
|
||||
// Desc: Destructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CMultiplayerInputDeviceManager::~CMultiplayerInputDeviceManager()
|
||||
{
|
||||
Cleanup();
|
||||
|
||||
if( m_bCleanupCOM )
|
||||
CoUninitialize();
|
||||
|
||||
RegCloseKey( m_hKey );
|
||||
|
||||
free( m_strKey );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: Create
|
||||
// Desc: Initializes the class, and enums the devices. See MultiMapper sample
|
||||
// for how to use this class.
|
||||
// It might fail if there are too many players for the
|
||||
// number of devices availible, or if one player owns too many
|
||||
// devices preventing others from having a device. Its up the app
|
||||
// to prevent this or respond to this.
|
||||
// Note: strUserName should be a array of sz strings
|
||||
//-----------------------------------------------------------------------------
|
||||
HRESULT CMultiplayerInputDeviceManager::Create( HWND hWnd,
|
||||
TCHAR* strUserNames[],
|
||||
DWORD dwNumUsers,
|
||||
DIACTIONFORMAT* pdiaf,
|
||||
LPDIMANAGERCALLBACK AddDeviceCallback,
|
||||
LPVOID pCallbackParam,
|
||||
BOOL bResetOwnership,
|
||||
BOOL bResetMappings )
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
if( strUserNames == NULL || dwNumUsers == 0 )
|
||||
return E_INVALIDARG;
|
||||
|
||||
Cleanup();
|
||||
|
||||
// Store data
|
||||
m_hWnd = hWnd;
|
||||
|
||||
// Create and init the m_pUsers array
|
||||
m_dwNumUsers = dwNumUsers;
|
||||
m_pUsers = new PlayerInfo*[dwNumUsers];
|
||||
for( DWORD i=0; i<dwNumUsers; i++ )
|
||||
{
|
||||
m_pUsers[i] = new PlayerInfo;
|
||||
ZeroMemory( m_pUsers[i], sizeof(PlayerInfo) );
|
||||
m_pUsers[i]->dwPlayerIndex = i; // set the 0-based player index (for easy referencing)
|
||||
lstrcpyn( m_pUsers[i]->strPlayerName, strUserNames[i], MAX_PATH-1 );
|
||||
}
|
||||
|
||||
m_AddDeviceCallback = AddDeviceCallback;
|
||||
m_AddDeviceCallbackParam = pCallbackParam;
|
||||
|
||||
// Create the base DirectInput object
|
||||
if( FAILED( hr = DirectInput8Create( GetModuleHandle(NULL), DIRECTINPUT_VERSION,
|
||||
IID_IDirectInput8, (VOID**)&m_pDI, NULL ) ) )
|
||||
return DXTRACE_ERR_NOMSGBOX( TEXT("DirectInput8Create"), hr );
|
||||
|
||||
if( FAILED( hr = SetActionFormat( pdiaf, TRUE, bResetOwnership, bResetMappings ) ) )
|
||||
return DXTRACE_ERR_NOMSGBOX( TEXT("SetActionFormat"), hr );
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: SetActionFormat
|
||||
// Desc: Sets a new action format.
|
||||
// It re-enumerates the devices if bReenumerate
|
||||
// It resets the ownership of the devices if bResetOwnership
|
||||
// It resets the mapper actions of the devices if bResetMappings
|
||||
// This function may fail if there are too many players for the
|
||||
// number of devices availible, or if one player owns too many
|
||||
// devices preventing others from having a device. Its up the app
|
||||
// to prevent this or respond to this.
|
||||
//-----------------------------------------------------------------------------
|
||||
HRESULT CMultiplayerInputDeviceManager::SetActionFormat( DIACTIONFORMAT* pdiaf,
|
||||
BOOL bReenumerate,
|
||||
BOOL bResetOwnership,
|
||||
BOOL bResetMappings )
|
||||
{
|
||||
HRESULT hr;
|
||||
DWORD iPlayer;
|
||||
DWORD iDevice;
|
||||
|
||||
// Store the new action format
|
||||
m_pdiaf = pdiaf;
|
||||
|
||||
// Only destroy and re-enumerate devices if the caller explicitly wants to.
|
||||
// This isn't thread safe, so be sure not to have any other threads using
|
||||
// this data unless you redesign this class
|
||||
if( bReenumerate )
|
||||
{
|
||||
// Set all players to not have a device yet
|
||||
for( iPlayer=0; iPlayer<m_dwNumUsers; iPlayer++ )
|
||||
m_pUsers[iPlayer]->bFoundDeviceForPlayer = FALSE;
|
||||
|
||||
if( bResetOwnership )
|
||||
{
|
||||
// Set all devices as not assigned to a player
|
||||
for( iDevice=0; iDevice<m_dwNumDevices; iDevice++ )
|
||||
m_pDeviceList[iDevice].pPlayerInfo = NULL;
|
||||
|
||||
// Delete the device ownership keys
|
||||
DeleteDeviceOwnershipKeys();
|
||||
}
|
||||
|
||||
// Devices must be unacquired to have a new action map set.
|
||||
UnacquireDevices();
|
||||
|
||||
// Enumerate all available devices that map the pri 1 actions,
|
||||
// and store them in the m_pDeviceList array
|
||||
if( FAILED( hr = BuildDeviceList() ) )
|
||||
return DXTRACE_ERR_NOMSGBOX( TEXT("BuildDeviceList"), hr );
|
||||
|
||||
// Assign devices to any players that don't have devices
|
||||
// Some games may want to change this functionality.
|
||||
if( FAILED( hr = AssignDevices() ) )
|
||||
return DXTRACE_ERR_NOMSGBOX( TEXT("AssignDevices"), hr );
|
||||
|
||||
// Report an error if there are too many players for the
|
||||
// number of devices availible, or if one player owns too many
|
||||
// devices preventing others from having a device
|
||||
if( FAILED( hr = VerifyAssignment() ) )
|
||||
return hr;
|
||||
|
||||
// Now that every player has at least one device, build and set
|
||||
// the action map, and use callback into the app to tell the
|
||||
// app of the device assignment.
|
||||
if( FAILED( hr = AddAssignedDevices( bResetMappings ) ) )
|
||||
return DXTRACE_ERR_NOMSGBOX( TEXT("AddAssignedDevices"), hr );
|
||||
|
||||
// For every device that's assigned to a player, save its device key
|
||||
// and assigned player to registry, so the app remembers which devices
|
||||
// each player prefers
|
||||
if( FAILED( hr = SaveDeviceOwnershipKeys() ) )
|
||||
return DXTRACE_ERR_NOMSGBOX( TEXT("SaveDeviceOwnershipKeys"), hr );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Just apply the new maps for each device owned by each user
|
||||
|
||||
// Devices must be unacquired to have a new action map set.
|
||||
UnacquireDevices();
|
||||
|
||||
// Apply the new action map to the current devices.
|
||||
for( iDevice=0; iDevice<m_dwNumDevices; iDevice++ )
|
||||
{
|
||||
LPDIRECTINPUTDEVICE8 pdidDevice = m_pDeviceList[iDevice].pdidDevice;
|
||||
PlayerInfo* pPlayerInfo = m_pDeviceList[iDevice].pPlayerInfo;
|
||||
|
||||
if( FAILED( hr = pdidDevice->BuildActionMap( m_pdiaf, pPlayerInfo->strPlayerName, DIDBAM_DEFAULT ) ) )
|
||||
return DXTRACE_ERR_NOMSGBOX( TEXT("BuildActionMap"), hr );
|
||||
if( FAILED( hr = pdidDevice->SetActionMap( m_pdiaf, pPlayerInfo->strPlayerName, DIDSAM_DEFAULT ) ) )
|
||||
return DXTRACE_ERR_NOMSGBOX( TEXT("SetActionMap"), hr );
|
||||
}
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: BuildDeviceList
|
||||
// Desc:
|
||||
//-----------------------------------------------------------------------------
|
||||
HRESULT CMultiplayerInputDeviceManager::BuildDeviceList()
|
||||
{
|
||||
// Cleanup any previously enumerated devices
|
||||
CleanupDeviceList();
|
||||
|
||||
// Build a simple list of all devices currently attached to the machine. This
|
||||
// array will be used to reassign devices to each user.
|
||||
m_dwMaxDevices = 5;
|
||||
m_dwNumDevices = 0;
|
||||
m_pDeviceList = NULL;
|
||||
m_pDeviceList = (DeviceInfo*) realloc( m_pDeviceList, m_dwMaxDevices*sizeof(DeviceInfo) );
|
||||
ZeroMemory( m_pDeviceList, m_dwMaxDevices*sizeof(DeviceInfo) );
|
||||
|
||||
// Enumerate available devices for any user.
|
||||
m_pDI->EnumDevicesBySemantics( NULL, m_pdiaf, StaticEnumSuitableDevicesCB,
|
||||
this, DIEDBSFL_ATTACHEDONLY );
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: EnumSuitableDevicesCB
|
||||
// Desc: DirectInput device enumeratation callback. Calls AddDevice()
|
||||
// on each device enumerated.
|
||||
//-----------------------------------------------------------------------------
|
||||
BOOL CALLBACK CMultiplayerInputDeviceManager::StaticEnumSuitableDevicesCB( LPCDIDEVICEINSTANCE pdidi,
|
||||
LPDIRECTINPUTDEVICE8 pdidDevice,
|
||||
DWORD dwFlags, DWORD dwDeviceRemaining,
|
||||
VOID* pContext )
|
||||
{
|
||||
// Add the device to the device manager's internal list
|
||||
CMultiplayerInputDeviceManager* pInputDeviceManager = (CMultiplayerInputDeviceManager*)pContext;
|
||||
return pInputDeviceManager->EnumDevice( pdidi, pdidDevice,
|
||||
dwFlags, dwDeviceRemaining );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: EnumDevice
|
||||
// Desc: Enums each device to see if its suitable to add
|
||||
//-----------------------------------------------------------------------------
|
||||
BOOL CMultiplayerInputDeviceManager::EnumDevice( const DIDEVICEINSTANCE* pdidi,
|
||||
const LPDIRECTINPUTDEVICE8 pdidDevice,
|
||||
DWORD dwFlags, DWORD dwRemainingDevices )
|
||||
{
|
||||
TCHAR strPlayerName[MAX_PATH];
|
||||
TCHAR strDeviceGuid[40];
|
||||
|
||||
// Devices of type DI8DEVTYPE_DEVICECTRL are specialized devices not generally
|
||||
// considered appropriate to control game actions. We just ignore these.
|
||||
if( GET_DIDEVICE_TYPE(pdidi->dwDevType) != DI8DEVTYPE_DEVICECTRL )
|
||||
{
|
||||
// We're only interested in devices that map the pri 1 actions
|
||||
if( dwFlags & DIEDBS_MAPPEDPRI1 )
|
||||
{
|
||||
// Add new pdidDevice struct to array, and resize array if needed
|
||||
m_dwNumDevices++;
|
||||
if( m_dwNumDevices > m_dwMaxDevices )
|
||||
{
|
||||
m_dwMaxDevices += 5;
|
||||
m_pDeviceList = (DeviceInfo*) realloc( m_pDeviceList, m_dwMaxDevices*sizeof(DeviceInfo) );
|
||||
ZeroMemory( m_pDeviceList + m_dwMaxDevices - 5, 5*sizeof(DeviceInfo) );
|
||||
}
|
||||
|
||||
DXUtil_ConvertGUIDToString( &pdidi->guidInstance, strDeviceGuid );
|
||||
DXUtil_ReadStringRegKey( m_hKey, strDeviceGuid, strPlayerName, MAX_PATH, TEXT("") );
|
||||
|
||||
// Add the device to the array m_pDeviceList
|
||||
DWORD dwCurrentDevice = m_dwNumDevices-1;
|
||||
ZeroMemory( &m_pDeviceList[dwCurrentDevice], sizeof(DeviceInfo) );
|
||||
|
||||
m_pDeviceList[dwCurrentDevice].didi = *pdidi;
|
||||
m_pDeviceList[dwCurrentDevice].pdidDevice = pdidDevice;
|
||||
m_pDeviceList[dwCurrentDevice].pdidDevice->AddRef();
|
||||
m_pDeviceList[dwCurrentDevice].bMapsPri1Actions = ((dwFlags & DIEDBS_MAPPEDPRI1) == DIEDBS_MAPPEDPRI1);
|
||||
m_pDeviceList[dwCurrentDevice].bMapsPri2Actions = ((dwFlags & DIEDBS_MAPPEDPRI2) == DIEDBS_MAPPEDPRI2);
|
||||
|
||||
if( lstrcmp( strPlayerName, TEXT("") ) != 0 )
|
||||
{
|
||||
m_pDeviceList[dwCurrentDevice].pPlayerInfo = LookupPlayer( strPlayerName );
|
||||
if( m_pDeviceList[dwCurrentDevice].pPlayerInfo )
|
||||
m_pDeviceList[dwCurrentDevice].pPlayerInfo->bFoundDeviceForPlayer = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Continue enumerating
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: AssignDevices
|
||||
// Desc:
|
||||
//-----------------------------------------------------------------------------
|
||||
HRESULT CMultiplayerInputDeviceManager::AssignDevices()
|
||||
{
|
||||
DWORD iDevice;
|
||||
DWORD iPlayer;
|
||||
|
||||
// For any device that doesn't have a user assigned to it,
|
||||
// then assign it to the first user that needs a device
|
||||
for( iDevice=0; iDevice<m_dwNumDevices; iDevice++ )
|
||||
{
|
||||
if( m_pDeviceList[iDevice].pPlayerInfo == NULL )
|
||||
{
|
||||
for( iPlayer=0; iPlayer<m_dwNumUsers; iPlayer++ )
|
||||
{
|
||||
if( !m_pUsers[iPlayer]->bFoundDeviceForPlayer )
|
||||
{
|
||||
m_pDeviceList[iDevice].pPlayerInfo = m_pUsers[iPlayer];
|
||||
m_pUsers[iPlayer]->bFoundDeviceForPlayer = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: VerifyAssignment
|
||||
// Desc:
|
||||
//-----------------------------------------------------------------------------
|
||||
HRESULT CMultiplayerInputDeviceManager::VerifyAssignment()
|
||||
{
|
||||
DWORD iPlayer;
|
||||
DWORD iDevice;
|
||||
|
||||
// For each player, make sure that a device was found for this
|
||||
// player, otherwise return failure.
|
||||
for( iPlayer=0; iPlayer<m_dwNumUsers; iPlayer++ )
|
||||
{
|
||||
if( !m_pUsers[iPlayer]->bFoundDeviceForPlayer )
|
||||
{
|
||||
if( GetNumDevices() < m_dwNumUsers )
|
||||
return E_DIUTILERR_TOOMANYUSERS;
|
||||
else
|
||||
{
|
||||
// Check to see if there's a device that isn't already
|
||||
// assigned to a player. If there is return
|
||||
// E_DIUTILERR_PLAYERWITHOUTDEVICE otherwise return
|
||||
// E_DIUTILERR_DEVICESTAKEN
|
||||
for( iDevice=0; iDevice<m_dwNumDevices; iDevice++ )
|
||||
{
|
||||
if( m_pDeviceList[iDevice].pPlayerInfo == NULL )
|
||||
return E_DIUTILERR_PLAYERWITHOUTDEVICE;
|
||||
}
|
||||
|
||||
return E_DIUTILERR_DEVICESTAKEN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: AddAssignedDevices
|
||||
// Desc: For every device that's assigned to a player, set it action map
|
||||
// and add it to the game
|
||||
//-----------------------------------------------------------------------------
|
||||
HRESULT CMultiplayerInputDeviceManager::AddAssignedDevices( BOOL bResetMappings )
|
||||
{
|
||||
DWORD iDevice;
|
||||
DWORD iAction;
|
||||
HRESULT hr = S_OK;
|
||||
DWORD *pdwAppFixed = NULL;
|
||||
|
||||
// If flagged, we'll be remapping the actions to hardware defaults, and in
|
||||
// the process DirectInput will clear the DIA_APPFIXED flag, so we need
|
||||
// to make a copy in order to reapply the flag later.
|
||||
if( bResetMappings )
|
||||
{
|
||||
pdwAppFixed = new DWORD[m_pdiaf->dwNumActions];
|
||||
|
||||
// Verify memory allocation and collect DIA_APPFIXED settings
|
||||
if( pdwAppFixed )
|
||||
{
|
||||
for( iAction=0; iAction < m_pdiaf->dwNumActions; iAction++ )
|
||||
pdwAppFixed[iAction] = m_pdiaf->rgoAction[iAction].dwFlags & DIA_APPFIXED;
|
||||
}
|
||||
}
|
||||
|
||||
// For every device that's assigned to a player,
|
||||
// set it action map, and add it to the game
|
||||
for( iDevice=0; iDevice<m_dwNumDevices; iDevice++ )
|
||||
{
|
||||
LPDIRECTINPUTDEVICE8 pdidDevice = m_pDeviceList[iDevice].pdidDevice;
|
||||
PlayerInfo* pPlayerInfo = m_pDeviceList[iDevice].pPlayerInfo;
|
||||
|
||||
if( pPlayerInfo != NULL )
|
||||
{
|
||||
// Set the device's coop level
|
||||
hr = pdidDevice->SetCooperativeLevel( m_hWnd, DISCL_NONEXCLUSIVE|DISCL_FOREGROUND );
|
||||
if( FAILED(hr) )
|
||||
break;
|
||||
|
||||
// Build and set the action map on this device. This will also remove
|
||||
// it from DirectInput's internal list of available devices.
|
||||
DWORD dwBuildFlags = bResetMappings ? DIDBAM_HWDEFAULTS : DIDBAM_DEFAULT;
|
||||
DWORD dwSetFlags = bResetMappings ? DIDSAM_FORCESAVE : DIDSAM_DEFAULT;
|
||||
|
||||
hr = pdidDevice->BuildActionMap( m_pdiaf, pPlayerInfo->strPlayerName, dwBuildFlags );
|
||||
if( FAILED( hr ) )
|
||||
{
|
||||
// just print out a debug message and keep going
|
||||
DXTRACE_ERR_NOMSGBOX( TEXT("BuildActionMap"), hr );
|
||||
hr = S_OK;
|
||||
continue;
|
||||
}
|
||||
|
||||
hr = pdidDevice->SetActionMap( m_pdiaf, pPlayerInfo->strPlayerName, dwSetFlags );
|
||||
if( FAILED( hr ) )
|
||||
{
|
||||
// just print out a debug message and keep going
|
||||
DXTRACE_ERR_NOMSGBOX( TEXT("SetActionMap"), hr );
|
||||
hr = S_OK;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// Callback into the app so it can adjust the device and set
|
||||
// the m_pDeviceList[iDevice].pParam field with a device state struct
|
||||
if( m_AddDeviceCallback )
|
||||
m_AddDeviceCallback( pPlayerInfo, &m_pDeviceList[iDevice],
|
||||
&m_pDeviceList[iDevice].didi, m_AddDeviceCallbackParam );
|
||||
|
||||
// Check to see if the device is using relative axis -- sometimes app code
|
||||
// might want to know this.
|
||||
DIPROPDWORD dipdw;
|
||||
dipdw.diph.dwSize = sizeof(DIPROPDWORD);
|
||||
dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
|
||||
dipdw.diph.dwObj = 0;
|
||||
dipdw.diph.dwHow = DIPH_DEVICE;
|
||||
dipdw.dwData = 0;
|
||||
pdidDevice->GetProperty( DIPROP_AXISMODE, &dipdw.diph );
|
||||
if( dipdw.dwData == DIPROPAXISMODE_REL )
|
||||
m_pDeviceList[iDevice].bRelativeAxis = TRUE;
|
||||
|
||||
// We made it through this iteration without breaking out do to errors
|
||||
hr = S_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( FAILED( hr = pdidDevice->BuildActionMap( m_pdiaf, NULL, DIDBAM_DEFAULT ) ) )
|
||||
{
|
||||
DXTRACE_ERR_NOMSGBOX( TEXT("BuildActionMap"), hr );
|
||||
break;
|
||||
}
|
||||
|
||||
if( FAILED( hr = pdidDevice->SetActionMap( m_pdiaf, NULL, DIDSAM_NOUSER ) ) )
|
||||
{
|
||||
DXTRACE_ERR_NOMSGBOX( TEXT("SetActionMap"), hr );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we stored DIA_APPFIXED flags earlier, we need to reapply those flags and
|
||||
// free the allocated memory
|
||||
if( bResetMappings && pdwAppFixed )
|
||||
{
|
||||
for( iAction=0; iAction < m_pdiaf->dwNumActions; iAction++ )
|
||||
m_pdiaf->rgoAction[iAction].dwFlags |= pdwAppFixed[iAction];
|
||||
|
||||
delete [] pdwAppFixed;
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: ConfigureDevices
|
||||
// Desc:
|
||||
//-----------------------------------------------------------------------------
|
||||
HRESULT CMultiplayerInputDeviceManager::ConfigureDevices( HWND hWnd, IUnknown* pSurface,
|
||||
VOID* ConfigureDevicesCB,
|
||||
DWORD dwFlags, LPVOID pvCBParam )
|
||||
{
|
||||
HRESULT hr;
|
||||
DWORD iPlayer;
|
||||
|
||||
// Determine how large of a string we'll need to hold all user names
|
||||
DWORD dwNamesSize = 0;
|
||||
for( iPlayer=0; iPlayer < m_dwNumUsers; iPlayer++ )
|
||||
dwNamesSize += lstrlen( m_pUsers[iPlayer]->strPlayerName ) +1;
|
||||
|
||||
// Build multi-sz list of user names
|
||||
TCHAR* strUserNames = new TCHAR[dwNamesSize+1];
|
||||
|
||||
// Verify allocation and cycle through user names
|
||||
if( strUserNames )
|
||||
{
|
||||
TCHAR* strTemp = strUserNames;
|
||||
for( iPlayer=0; iPlayer<m_dwNumUsers; iPlayer++ )
|
||||
{
|
||||
lstrcpy( strTemp, m_pUsers[iPlayer]->strPlayerName );
|
||||
strTemp += lstrlen(strTemp) + 1;
|
||||
}
|
||||
|
||||
lstrcpy( strTemp, TEXT("\0") );
|
||||
}
|
||||
|
||||
|
||||
// Fill in all the params
|
||||
DICONFIGUREDEVICESPARAMS dicdp;
|
||||
ZeroMemory(&dicdp, sizeof(dicdp));
|
||||
dicdp.dwSize = sizeof(dicdp);
|
||||
dicdp.dwcFormats = 1;
|
||||
dicdp.lprgFormats = m_pdiaf;
|
||||
dicdp.hwnd = hWnd;
|
||||
dicdp.lpUnkDDSTarget = pSurface;
|
||||
dicdp.dwcUsers = m_dwNumUsers;
|
||||
dicdp.lptszUserNames = strUserNames;
|
||||
|
||||
// Initialize all the colors here
|
||||
DICOLORSET dics;
|
||||
ZeroMemory(&dics, sizeof(DICOLORSET));
|
||||
dics.dwSize = sizeof(DICOLORSET);
|
||||
|
||||
// Set UI color scheme (if not specified it uses defaults)
|
||||
dicdp.dics.dwSize = sizeof(dics);
|
||||
dicdp.dics.cTextFore = D3DCOLOR_RGBA(255,255,255,255);
|
||||
dicdp.dics.cTextHighlight = D3DCOLOR_RGBA(60,191,241,255);
|
||||
dicdp.dics.cCalloutLine = D3DCOLOR_RGBA(255,255,255,128);
|
||||
dicdp.dics.cCalloutHighlight= D3DCOLOR_RGBA(60,191,241,255);
|
||||
dicdp.dics.cBorder = D3DCOLOR_RGBA(140,152,140,128);
|
||||
dicdp.dics.cControlFill = D3DCOLOR_RGBA(113,0,0,128);
|
||||
dicdp.dics.cHighlightFill = D3DCOLOR_RGBA(0,0,0,128);
|
||||
dicdp.dics.cAreaFill = D3DCOLOR_RGBA(0,0,0,128);
|
||||
|
||||
if( dwFlags & DICD_EDIT )
|
||||
{
|
||||
// Re-enum so we can catch any new devices that have been recently attached
|
||||
for( iPlayer=0; iPlayer<m_dwNumUsers; iPlayer++ )
|
||||
m_pUsers[iPlayer]->bFoundDeviceForPlayer = FALSE;
|
||||
if( FAILED( hr = BuildDeviceList() ) )
|
||||
{
|
||||
DXTRACE_ERR_NOMSGBOX( TEXT("BuildDeviceList"), hr );
|
||||
goto LCleanup;
|
||||
}
|
||||
}
|
||||
|
||||
// Unacquire the devices so that mouse doesn't
|
||||
// control the game while in control panel
|
||||
UnacquireDevices();
|
||||
|
||||
if( FAILED( hr = m_pDI->ConfigureDevices( (LPDICONFIGUREDEVICESCALLBACK)ConfigureDevicesCB,
|
||||
&dicdp, dwFlags, pvCBParam ) ) )
|
||||
{
|
||||
DXTRACE_ERR_NOMSGBOX( TEXT("ConfigureDevices"), hr );
|
||||
goto LCleanup;
|
||||
}
|
||||
|
||||
if( dwFlags & DICD_EDIT )
|
||||
{
|
||||
// Update the device ownership
|
||||
if( FAILED( hr = UpdateDeviceOwnership() ) )
|
||||
{
|
||||
DXTRACE_ERR_NOMSGBOX( TEXT("UpdateDeviceOwnership"), hr );
|
||||
goto LCleanup;
|
||||
}
|
||||
|
||||
// Now save the device keys that are assigned players to registry,
|
||||
if( FAILED( hr = SaveDeviceOwnershipKeys() ) )
|
||||
{
|
||||
DXTRACE_ERR_NOMSGBOX( TEXT("SaveDeviceOwnershipKeys"), hr );
|
||||
goto LCleanup;
|
||||
}
|
||||
|
||||
// Report an error if there is a player that doesn't not
|
||||
// have a device assigned
|
||||
if( FAILED( hr = VerifyAssignment() ) )
|
||||
goto LCleanup;
|
||||
|
||||
// Now that every player has at least one device, build and set
|
||||
// the action map, and use callback into the app to tell the
|
||||
// app of the device assignment.
|
||||
if( FAILED( hr = AddAssignedDevices( FALSE ) ) )
|
||||
{
|
||||
DXTRACE_ERR_NOMSGBOX( TEXT("AddAssignedDevices"), hr );
|
||||
goto LCleanup;
|
||||
}
|
||||
}
|
||||
|
||||
hr = S_OK;
|
||||
|
||||
LCleanup:
|
||||
|
||||
if( strUserNames )
|
||||
delete [] strUserNames;
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: UpdateDeviceOwnership
|
||||
// Desc:
|
||||
//-----------------------------------------------------------------------------
|
||||
HRESULT CMultiplayerInputDeviceManager::UpdateDeviceOwnership()
|
||||
{
|
||||
DWORD iPlayer;
|
||||
DWORD iDevice;
|
||||
|
||||
// Set all players to not have a device yet
|
||||
for( iPlayer=0; iPlayer<m_dwNumUsers; iPlayer++ )
|
||||
m_pUsers[iPlayer]->bFoundDeviceForPlayer = FALSE;
|
||||
|
||||
// Set all devices as not assigned to a player
|
||||
for( iDevice=0; iDevice<m_dwNumDevices; iDevice++ )
|
||||
m_pDeviceList[iDevice].pPlayerInfo = NULL;
|
||||
|
||||
UnacquireDevices();
|
||||
|
||||
// Update the device ownership by quering the DIPROP_USERNAME property
|
||||
for( iDevice=0; iDevice<m_dwNumDevices; iDevice++ )
|
||||
{
|
||||
LPDIRECTINPUTDEVICE8 pdidDevice = m_pDeviceList[iDevice].pdidDevice;
|
||||
|
||||
TCHAR strPlayerName[MAX_PATH];
|
||||
DIPROPSTRING dips;
|
||||
dips.diph.dwSize = sizeof(DIPROPSTRING);
|
||||
dips.diph.dwHeaderSize = sizeof(DIPROPHEADER);
|
||||
dips.diph.dwObj = 0; // device property
|
||||
dips.diph.dwHow = DIPH_DEVICE;
|
||||
pdidDevice->GetProperty( DIPROP_USERNAME, &dips.diph );
|
||||
DXUtil_ConvertWideStringToGeneric( strPlayerName, dips.wsz );
|
||||
|
||||
if( lstrcmp( strPlayerName, TEXT("") ) != 0 )
|
||||
{
|
||||
m_pDeviceList[iDevice].pPlayerInfo = LookupPlayer( strPlayerName );
|
||||
if( m_pDeviceList[iDevice].pPlayerInfo )
|
||||
m_pDeviceList[iDevice].pPlayerInfo->bFoundDeviceForPlayer = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: UnacquireDevices
|
||||
// Desc:
|
||||
//-----------------------------------------------------------------------------
|
||||
VOID CMultiplayerInputDeviceManager::UnacquireDevices()
|
||||
{
|
||||
// Unacquire every device
|
||||
|
||||
if( m_pDeviceList )
|
||||
{
|
||||
// All devices have been assigned a to a user in
|
||||
// the new array, so clean up the local array
|
||||
for( DWORD iDevice=0; iDevice<m_dwNumDevices; iDevice++ )
|
||||
{
|
||||
LPDIRECTINPUTDEVICE8 pdidDevice = m_pDeviceList[iDevice].pdidDevice;
|
||||
|
||||
// Set the device's coop level
|
||||
pdidDevice->Unacquire();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: SetFocus
|
||||
// Desc: Sets the DirectInput focus to a new HWND
|
||||
//-----------------------------------------------------------------------------
|
||||
VOID CMultiplayerInputDeviceManager::SetFocus( HWND hWnd )
|
||||
{
|
||||
m_hWnd = hWnd;
|
||||
|
||||
if( m_pDeviceList )
|
||||
{
|
||||
// All devices have been assigned a to a user in
|
||||
// the new array, so clean up the local array
|
||||
for( DWORD iDevice=0; iDevice<m_dwNumDevices; iDevice++ )
|
||||
{
|
||||
LPDIRECTINPUTDEVICE8 pdidDevice = m_pDeviceList[iDevice].pdidDevice;
|
||||
|
||||
// Set the device's coop level
|
||||
pdidDevice->Unacquire();
|
||||
pdidDevice->SetCooperativeLevel( m_hWnd, DISCL_NONEXCLUSIVE|DISCL_FOREGROUND );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: GetDevices
|
||||
// Desc: returns an array of DeviceInfo*'s
|
||||
//-----------------------------------------------------------------------------
|
||||
HRESULT CMultiplayerInputDeviceManager::GetDevices( DeviceInfo** ppDeviceInfo,
|
||||
DWORD* pdwCount )
|
||||
{
|
||||
if( NULL==ppDeviceInfo || NULL==pdwCount )
|
||||
return E_INVALIDARG;
|
||||
|
||||
(*ppDeviceInfo) = m_pDeviceList;
|
||||
(*pdwCount) = m_dwNumDevices;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: LookupPlayer
|
||||
// Desc: searchs m_pUsers by player name
|
||||
//-----------------------------------------------------------------------------
|
||||
CMultiplayerInputDeviceManager::PlayerInfo* CMultiplayerInputDeviceManager::LookupPlayer( TCHAR* strPlayerName )
|
||||
{
|
||||
for( DWORD iPlayer=0; iPlayer<m_dwNumUsers; iPlayer++ )
|
||||
{
|
||||
PlayerInfo* pCurPlayer = m_pUsers[iPlayer];
|
||||
if( lstrcmp( pCurPlayer->strPlayerName, strPlayerName ) == 0 )
|
||||
return pCurPlayer;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: SaveDeviceOwnershipKeys
|
||||
// Desc: For every device that's assigned to a player, save its device key
|
||||
// and assigned player to registry.
|
||||
//-----------------------------------------------------------------------------
|
||||
HRESULT CMultiplayerInputDeviceManager::SaveDeviceOwnershipKeys()
|
||||
{
|
||||
TCHAR strDeviceGuid[40];
|
||||
DWORD iDevice;
|
||||
|
||||
for( iDevice=0; iDevice<m_dwNumDevices; iDevice++ )
|
||||
{
|
||||
PlayerInfo* pPlayerInfo = m_pDeviceList[iDevice].pPlayerInfo;
|
||||
|
||||
DXUtil_ConvertGUIDToString( &m_pDeviceList[iDevice].didi.guidInstance, strDeviceGuid );
|
||||
|
||||
if( pPlayerInfo != NULL )
|
||||
DXUtil_WriteStringRegKey( m_hKey, strDeviceGuid, pPlayerInfo->strPlayerName );
|
||||
else
|
||||
RegDeleteValue( m_hKey, strDeviceGuid );
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: DeleteDeviceOwnershipKeys
|
||||
// Desc: Delete all the ownership keys
|
||||
//-----------------------------------------------------------------------------
|
||||
VOID CMultiplayerInputDeviceManager::DeleteDeviceOwnershipKeys()
|
||||
{
|
||||
HKEY hKey;
|
||||
TCHAR *strRegKey;
|
||||
|
||||
// Prepare strings to delete the key
|
||||
strRegKey = _tcsdup( m_strKey );
|
||||
if( strRegKey == NULL )
|
||||
return;
|
||||
|
||||
TCHAR* strTemp = _tcsrchr( strRegKey, TEXT('\\') );
|
||||
|
||||
// Unless the registry path string was malformed, we're ready to delete
|
||||
// and recreate the key
|
||||
if( strTemp )
|
||||
{
|
||||
*strTemp = 0;
|
||||
strTemp++;
|
||||
|
||||
RegCloseKey( m_hKey );
|
||||
|
||||
// Delete the reg key
|
||||
RegOpenKey( HKEY_CURRENT_USER, strRegKey, &hKey );
|
||||
SHDeleteKey( hKey, strTemp );
|
||||
RegCloseKey( hKey );
|
||||
|
||||
// Create the key again now that all the subkeys have been deleted
|
||||
RegCreateKeyEx( HKEY_CURRENT_USER, m_strKey, 0, NULL,
|
||||
REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
|
||||
&m_hKey, NULL );
|
||||
}
|
||||
|
||||
|
||||
// Clean up memory allocation
|
||||
free( strRegKey );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: Cleanup
|
||||
// Desc:
|
||||
//-----------------------------------------------------------------------------
|
||||
VOID CMultiplayerInputDeviceManager::Cleanup()
|
||||
{
|
||||
CleanupDeviceList();
|
||||
|
||||
if( m_pUsers )
|
||||
{
|
||||
for( DWORD iPlayer=0; iPlayer<m_dwNumUsers; iPlayer++ )
|
||||
SAFE_DELETE( m_pUsers[iPlayer] );
|
||||
SAFE_DELETE( m_pUsers );
|
||||
}
|
||||
|
||||
// Release() base object
|
||||
SAFE_RELEASE( m_pDI );
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: CleanupDeviceList
|
||||
// Desc: Clean up the device array
|
||||
//-----------------------------------------------------------------------------
|
||||
VOID CMultiplayerInputDeviceManager::CleanupDeviceList()
|
||||
{
|
||||
for( DWORD iDevice=0; iDevice<m_dwNumDevices; iDevice++ )
|
||||
SAFE_RELEASE( m_pDeviceList[iDevice].pdidDevice );
|
||||
free( m_pDeviceList );
|
||||
m_pDeviceList = NULL;
|
||||
m_dwMaxDevices = 0;
|
||||
m_dwNumDevices = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// File: MultiDI.h
|
||||
//
|
||||
// Desc: Multiple user DirectInput support using action mapping
|
||||
//
|
||||
// Copyright (C) 1995-2001 Microsoft Corporation. All Rights Reserved.
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifndef MULTIDI_H
|
||||
#define MULTIDI_H
|
||||
#include <dinput.h>
|
||||
|
||||
|
||||
// E_DIUTILERR_PLAYERWITHOUTDEVICE is returned by the manager class after configuring
|
||||
// device, and there's a player that hasn't been assigned a device.
|
||||
#define E_DIUTILERR_PLAYERWITHOUTDEVICE MAKE_HRESULT(SEVERITY_ERROR,FACILITY_ITF,997)
|
||||
|
||||
// E_DIUTILERR_DEVICESTAKEN is returned by the manager class when one player
|
||||
// on the machine has enough RECENT devices to prevent other players from
|
||||
// playing. This return code is needed because this sample attempts to give
|
||||
// all RECENT devices to that player.
|
||||
#define E_DIUTILERR_DEVICESTAKEN MAKE_HRESULT(SEVERITY_ERROR,FACILITY_ITF,998)
|
||||
|
||||
// E_DIUTILERR_TOOMANYUSERS is returned by the manager class when the number of
|
||||
// players exceeds the number of devices present on the system. For example,
|
||||
// if you ask for 4 players on a machine that only has a keyboard and mouse,
|
||||
// you're 2 short of what you need.
|
||||
#define E_DIUTILERR_TOOMANYUSERS MAKE_HRESULT(SEVERITY_ERROR,FACILITY_ITF,999)
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: class CMultiplayerInputDeviceManager
|
||||
// Desc: Input device manager using DX8 action mapping
|
||||
//-----------------------------------------------------------------------------
|
||||
class CMultiplayerInputDeviceManager
|
||||
{
|
||||
public:
|
||||
struct PlayerInfo
|
||||
{
|
||||
DWORD dwPlayerIndex; // 0-based player number
|
||||
TCHAR strPlayerName[MAX_PATH]; // player name
|
||||
DWORD dwMaxDevices; // max number of elements in pDevices array
|
||||
DWORD dwNumDevices; // current number of elements in pDevices array
|
||||
BOOL bFoundDeviceForPlayer; // if a device has been found for this player yet
|
||||
};
|
||||
|
||||
struct DeviceInfo
|
||||
{
|
||||
LPDIRECTINPUTDEVICE8 pdidDevice; // dinput device pointer
|
||||
PlayerInfo* pPlayerInfo; // Player who owns this device
|
||||
BOOL bRelativeAxis; // TRUE if device is using relative axis
|
||||
BOOL bMapsPri1Actions; // TRUE if device maps pri 1 actions
|
||||
BOOL bMapsPri2Actions; // TRUE if device maps pri 2 actions
|
||||
LPVOID pParam; // app defined pointer assoicated with this device
|
||||
DIDEVICEINSTANCE didi; // device instance info
|
||||
};
|
||||
|
||||
typedef HRESULT (CALLBACK *LPDIMANAGERCALLBACK)(CMultiplayerInputDeviceManager::PlayerInfo* pPlayerInfo, CMultiplayerInputDeviceManager::DeviceInfo* pDeviceInfo, const DIDEVICEINSTANCE* pdidi, LPVOID);
|
||||
|
||||
private:
|
||||
BOOL m_bCleanupCOM;
|
||||
HWND m_hWnd;
|
||||
|
||||
LPDIRECTINPUT8 m_pDI;
|
||||
DIACTIONFORMAT* m_pdiaf;
|
||||
|
||||
PlayerInfo** m_pUsers;
|
||||
DWORD m_dwNumUsers;
|
||||
|
||||
DeviceInfo* m_pDeviceList;
|
||||
DWORD m_dwNumDevices;
|
||||
DWORD m_dwMaxDevices;
|
||||
|
||||
LPDIMANAGERCALLBACK m_AddDeviceCallback;
|
||||
LPVOID m_AddDeviceCallbackParam;
|
||||
|
||||
TCHAR* m_strKey;
|
||||
HKEY m_hKey;
|
||||
|
||||
public:
|
||||
static BOOL CALLBACK StaticEnumSuitableDevicesCB( LPCDIDEVICEINSTANCE pdidi, LPDIRECTINPUTDEVICE8 pdidDevice, DWORD dwFlags, DWORD dwRemainingDevices, VOID* pContext );
|
||||
static BOOL CALLBACK StaticBuildDeviceListCB( LPCDIDEVICEINSTANCE pdidi, VOID* pContext );
|
||||
|
||||
// Device control
|
||||
BOOL EnumDevice( const DIDEVICEINSTANCE* pdidi, LPDIRECTINPUTDEVICE8 pdidDevice, DWORD dwFlags, DWORD dwDeviceRemaining );
|
||||
BOOL BuildDeviceListCB( LPCDIDEVICEINSTANCE pdidi );
|
||||
|
||||
HRESULT AddDevice( DeviceInfo* pDeviceInfo, BOOL bForceReset );
|
||||
HRESULT GetDevices( DeviceInfo** ppDeviceInfo, DWORD* pdwNumDevices );
|
||||
HRESULT ConfigureDevices( HWND hWnd, IUnknown* pSurface, VOID* pCallback, DWORD dwFlags, LPVOID pvCBParam );
|
||||
DWORD GetNumDevices() { return m_dwNumDevices; }
|
||||
VOID UnacquireDevices();
|
||||
VOID SetFocus( HWND hWnd );
|
||||
PlayerInfo* LookupPlayer( TCHAR* strPlayerName );
|
||||
HRESULT SaveDeviceOwnershipKeys();
|
||||
VOID DeleteDeviceOwnershipKeys();
|
||||
HRESULT UpdateDeviceOwnership();
|
||||
HRESULT AssignDevices();
|
||||
HRESULT VerifyAssignment();
|
||||
HRESULT AddAssignedDevices( BOOL bResetMappings );
|
||||
|
||||
HRESULT BuildDeviceList();
|
||||
VOID CleanupDeviceList();
|
||||
|
||||
// Construction
|
||||
HRESULT SetActionFormat( DIACTIONFORMAT* pdiaf, BOOL bReenumerate, BOOL bResetOwnership, BOOL bResetMappings );
|
||||
HRESULT Create( HWND hWnd, TCHAR* strUserNames[], DWORD dwNumUsers, DIACTIONFORMAT* pdiaf, LPDIMANAGERCALLBACK AddDeviceCallback, LPVOID pCallbackParam, BOOL bResetOwnership, BOOL bResetMappings );
|
||||
|
||||
CMultiplayerInputDeviceManager( TCHAR* strRegKey );
|
||||
~CMultiplayerInputDeviceManager();
|
||||
VOID Cleanup();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,53 @@
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Developer Studio generated include file.
|
||||
// Used by MultiMapper.rc
|
||||
//
|
||||
#define IDC_RESET_OWNERSHIP 3
|
||||
#define IDC_RESET_MAPPINGS 4
|
||||
#define IDI_MAIN_ICON 101
|
||||
#define IDD_MAIN 101
|
||||
#define IDI_MAIN 101
|
||||
#define IDC_UD_AXIS_STATE_P1 1031
|
||||
#define IDC_LR_AXIS_STATE_P1 1032
|
||||
#define IDC_BUTTON_STATE_P1 1034
|
||||
#define IDC_NUM_PLAYERS_COMBO 1035
|
||||
#define IDC_PLAYER4_GROUP 1036
|
||||
#define IDC_PLAYER3_GROUP 1037
|
||||
#define IDC_PLAYER1_GROUP 1038
|
||||
#define IDC_PLAYER2_GROUP 1039
|
||||
#define IDC_UD_AXIS_STATE_P2 1040
|
||||
#define IDC_LR_AXIS_STATE_P2 1041
|
||||
#define IDC_BUTTON_STATE_P2 1042
|
||||
#define IDC_UD_AXIS_STATE_P3 1043
|
||||
#define IDC_LR_AXIS_STATE_P3 1044
|
||||
#define IDC_BUTTON_STATE_P3 1045
|
||||
#define IDC_UD_AXIS_STATE_P4 1046
|
||||
#define IDC_LR_AXIS_STATE_P4 1047
|
||||
#define IDC_BUTTON_STATE_P4 1048
|
||||
#define IDC_WORLD_STATE 1049
|
||||
#define IDC_TEXT1_P2 1050
|
||||
#define IDC_TEXT2_P2 1051
|
||||
#define IDC_TEXT3_P2 1052
|
||||
#define IDC_TEXT1_P3 1053
|
||||
#define IDC_TEXT1_P4 1054
|
||||
#define IDC_TEXT2_P3 1055
|
||||
#define IDC_TEXT2_P4 1056
|
||||
#define IDC_TEXT3_P3 1057
|
||||
#define IDC_TEXT3_P4 1058
|
||||
#define IDC_DEVICE_ASSIGNED_P1 1069
|
||||
#define IDC_DEVICE_ASSIGNED_P2 1070
|
||||
#define IDC_DEVICE_ASSIGNED_P3 1071
|
||||
#define IDC_DEVICE_ASSIGNED_P4 1072
|
||||
#define IDM_CONFIGINPUT 40011
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_3D_CONTROLS 1
|
||||
#define _APS_NEXT_RESOURCE_VALUE 146
|
||||
#define _APS_NEXT_COMMAND_VALUE 40013
|
||||
#define _APS_NEXT_CONTROL_VALUE 1070
|
||||
#define _APS_NEXT_SYMED_VALUE 102
|
||||
#endif
|
||||
#endif
|
||||
Reference in New Issue
Block a user