Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2731 lines
80 KiB

/****************************************************************************
*
* Copyright (C) 2000, 2001 Microsoft Corporation. All Rights Reserved.
*
* Author: Tomislav Markoc, (tmarkoc), SDE
*
****************************************************************************/
#include <windows.h>
#include <commctrl.h>//UI only
#include <shfusion.h>//UI only
#define _INC_MMSYSTEM
#define WINMMAPI DECLSPEC_IMPORT
typedef UINT MMRESULT; /* error return code, 0 means no error */
/* call as if(err=xxxx(...)) Error(err); else */
// end of hack to avoid including mmsystem.h!!!
#include <gameport.h>
#include <dinput.h>
#include <dinputd.h>
#include <list>
#include <exception>
#include <string>
#include <algorithm>
#include <tchar.h>
#include <windowsx.h>
#include <regstr.h>
#include <new.h>
#include "resource.h"
#include "ifacesvr.h"
#include "joyarray.h"
using namespace std;
#define NUMJOYDEVS 16//Max joy id-s. Why is this hardcoded?
#define MAX_DEVICES 75
#define IDC_WHATSTHIS 400
#ifdef UNICODE
#define String wstring
#else
#define String string
#endif // !UNICODE
#ifdef _CHECKED
#define JOY_EXCEPTION(A) JoyException(_T(__FILE__),__LINE__,A)
#else
#define JOY_EXCEPTION(A) JoyException(A)
#endif
#define cA(a) (sizeof(a)/sizeof(a[0]))
class JoyException:public exception
{
HRESULT m_hRes;
#ifdef _CHECKED
String m_SourceFile;
DWORD m_dwLine;
#endif
public:
HRESULT GetResult(){return m_hRes;};
JoyException(
#ifdef _CHECKED
LPCTSTR lpSourceFile,DWORD dwLine,
#endif
HRESULT hRes);
};
JoyException::JoyException(
#ifdef _CHECKED
LPCTSTR lpSourceFile,DWORD dwLine,
#endif
HRESULT hRes)
{
m_hRes=hRes;
#ifdef _CHECKED
m_SourceFile=lpSourceFile;
m_dwLine=dwLine;
#endif
}
int __cdecl my_new_handler(size_t) {
throw JOY_EXCEPTION(E_OUTOFMEMORY);
return 0;
}
template <class p> class AutoRelease
{
p m_p;
public:
AutoRelease(){m_p=NULL;};
~AutoRelease(){Clear();};
void Clear(){
ULONG nRef=-1;
if(m_p)
{
nRef=m_p->Release();//If last ptr, nRef falls to 0.
};
m_p=NULL;};
AutoRelease(const AutoRelease<p> &R)
{m_p=R.m_p;m_p->AddRef();};
AutoRelease<p> &operator=(const AutoRelease<p> &R)
{m_p=R.m_p;m_p->AddRef();return *this;};
AutoRelease<p> &operator=(p ptr)
{m_p=ptr;if(m_p)m_p->AddRef();return *this;};
p operator->(){return m_p;};
operator p&(){return m_p;};
operator p*(){return &m_p;};
};
typedef AutoRelease<LPDIRECTINPUT8> LPDIRECTINPUT_AR;
typedef AutoRelease<LPDIRECTINPUTDEVICE8> LPDIRECTINPUTDEVICE_AR;
typedef AutoRelease<LPDIRECTINPUTJOYCONFIG8> LPDIRECTINPUTJOYCONFIG_AR;
template <class p> class AutoDeleteArray
{
p m_p;
public:
AutoDeleteArray(){m_p=NULL;};
AutoDeleteArray(const p P){m_p=P;};
~AutoDeleteArray(){delete[] m_p;};
p operator=(const p P){m_p=P;return m_p;};
p operator->(){return m_p;};
operator p&(){return m_p;};
operator p*(){return &m_p;};
};
enum EStatus{EConnected,ENotConnected,EUnknown};
//ISSUE-2001/03/29-timgill Should use predefined NULLGUID
const GUID NULLGUID;
class CCore;
class CDIDev
{
friend BOOL CALLBACK DIEnumDevicesProc(
const DIDEVICEINSTANCE * lpddi,LPVOID pvRef);
LPDIRECTINPUTDEVICE_AR m_pDID;
DIDEVICEINSTANCE m_DIDevInst;
DIDEVCAPS_DX3 m_DIDevCaps;
DIJOYCONFIG m_DIJoyCfg;
DWORD m_dwId;
bool m_bInitialized;
CCore *m_pCore;
public:
CDIDev(){m_bInitialized=false;};
DWORD Id(){return m_dwId;};
const GUID &InstGUID(){return m_DIDevInst.guidInstance;};
const GUID &PortGUID(){return m_DIJoyCfg.guidGameport;};
LPCTSTR InstName(){return m_DIDevInst.tszInstanceName;};
EStatus Status(){if(m_DIDevCaps.dwFlags&DIDC_ATTACHED)return EConnected;return ENotConnected;};
void Update(LPDIRECTINPUTJOYCONFIG8 pJoyCfg);
HRESULT Rename(LPCTSTR pName);
bool operator==(const GUID &G){if(InstGUID()==G)return true;return false;};
};
class CGprtDev
{
friend BOOL CALLBACK DIEnumJoyTypePr(LPCWSTR pwszTypeName,LPVOID pvRef);
friend class CCore;
String m_Name;
DIJOYTYPEINFO m_Info;
public:
LPCTSTR TypeName(){return m_Name.data();};
LPCTSTR Name(){return m_Info.wszDisplayName;};
bool operator==(LPCTSTR pTypeName){if(m_Name==pTypeName)return true;return false;};
bool Rudder(){if(m_Info.hws.dwFlags&JOY_HWS_HASR)return true;return false;};
};
typedef list<CDIDev> LISTDIDEV;
typedef list<String> LISTSTRING;
typedef list<CGprtDev> LISTGPRTDEV;
class CCore
{
friend HRESULT Properties(HMODULE hMod,HWND hWnd,CCore *pCore,DWORD dwId);
friend BOOL CALLBACK DIEnumJoyTypePr(LPCWSTR pwszTypeName,LPVOID pvRef);
friend class CDIDev;
friend BOOL CALLBACK DIEnumDevicesProc(const DIDEVICEINSTANCE *lpddi,LPVOID pvRef);
bool m_bAccess;
bool m_bInitialized;
virtual void UIUpdate(){};
LPDIRECTINPUT_AR m_pDI;
LPDIRECTINPUTJOYCONFIG_AR m_pDIJoyCfg;
int GetNextAvailableId();
bool FullJoyOemAccess();
public:
LISTDIDEV m_ListDIDev;
LISTSTRING m_GprtDrv;
LISTGPRTDEV m_GprtBus;
LISTGPRTDEV m_GprtDev;
CCore();
void Initialize(HWND hWnd);
void Update();
void UpdateType();
bool Access(){return m_bAccess;};
CDIDev *FindDIDev(GUID &G);
HRESULT Remove(GUID &G);
void Preferred(GUID &G);
HRESULT AddDevice
(LPCTSTR pTypeName,bool bRudder,LPCTSTR pGprtId,GUID &GOccupied);
bool IsAutoDetectGprt();
bool IsAvailableVIDPID(String &VIDPIDName);
bool DuplicateDeviceName(LPCTSTR pName);
void AddCustomDevice(bool bJoy,bool bPad,bool bYoke,bool bCar,
int nAxes,bool bZAxis,int nButtons,bool bHasPov,LPCTSTR pName,
LPCTSTR pVIDPIDName);
bool IsCustomDevice(LPCTSTR pTypeName);
bool IsDeviceActive(LPCTSTR pTypeName);
void DeleteType(LPCTSTR pTypeName);
CGprtDev *FindGprtDev(LPCTSTR pTypeName);
};
struct SEnumDev
{
LPDIRECTINPUT8 m_pDI;
CCore *m_pCore;
SEnumDev(LISTDIDEV &ListDIDev,LPDIRECTINPUT8 pDI,CCore *pCore)
{m_pDI=pDI;m_pCore=pCore;};
};
/******************************************************************************
End of header
******************************************************************************/
/******************************************************************************
CDIDev
******************************************************************************/
HRESULT CDIDev::Rename(LPCTSTR pName)
{
if(!m_bInitialized)
{
throw JOY_EXCEPTION(E_FAIL);
}
if(!m_pCore->Access())return DIERR_INSUFFICIENTPRIVS;
DIPROPSTRING DIPropString;
ZeroMemory(&DIPropString,sizeof(DIPROPSTRING));
DIPropString.diph.dwSize=sizeof(DIPROPSTRING);
DIPropString.diph.dwHeaderSize=sizeof(DIPROPHEADER);
DIPropString.diph.dwHow=DIPH_DEVICE;
wcsncpy(DIPropString.wsz,pName,MAX_PATH-1);
DIPropString.wsz[MAX_PATH-1]=0;
HRESULT hRes=m_pDID->SetProperty(DIPROP_INSTANCENAME,&DIPropString.diph);
Update(m_pCore->m_pDIJoyCfg);
return hRes;
}
void CDIDev::Update(LPDIRECTINPUTJOYCONFIG8 pJoyCfg)
{
HRESULT hRes=S_OK;
ZeroMemory(&m_DIDevInst,sizeof(m_DIDevInst));
m_DIDevInst.dwSize=sizeof(m_DIDevInst);
hRes=m_pDID->GetDeviceInfo(&m_DIDevInst);
if(FAILED(hRes))
{
throw JOY_EXCEPTION(hRes);
}
ZeroMemory(&m_DIDevCaps,sizeof(m_DIDevCaps));
m_DIDevCaps.dwSize=sizeof(m_DIDevCaps);
hRes=m_pDID->GetCapabilities((LPDIDEVCAPS)&m_DIDevCaps);
if(FAILED(hRes))
{
throw JOY_EXCEPTION(hRes);
}
//Get Id.
m_dwId=-1;
DIPROPDWORD DIPropDW;
ZeroMemory(&DIPropDW,sizeof(DIPropDW));
DIPropDW.diph.dwSize=sizeof(DIPROPDWORD);
DIPropDW.diph.dwHeaderSize=sizeof(DIPROPHEADER);
DIPropDW.diph.dwHow=DIPH_DEVICE;
hRes=m_pDID->GetProperty(DIPROP_JOYSTICKID,&DIPropDW.diph);
if(FAILED(hRes))
{
throw JOY_EXCEPTION(hRes);
}
m_dwId=DIPropDW.dwData;
//Get gameport.
ZeroMemory(&m_DIJoyCfg,sizeof(m_DIJoyCfg));
m_DIJoyCfg.dwSize=sizeof(m_DIJoyCfg);
hRes=pJoyCfg->GetConfig(m_dwId,&m_DIJoyCfg,DIJC_WDMGAMEPORT);
if(FAILED(hRes))
{
//throw JOY_EXCEPTION(hRes);
}
}
/******************************************************************************
CCore
******************************************************************************/
BOOL CALLBACK DIEnumDevicesProc(
const DIDEVICEINSTANCE *lpddi,LPVOID pvRef)
{
try
{
SEnumDev &ED=*(SEnumDev*)pvRef;
CDIDev Dev;
Dev.m_pCore=ED.m_pCore;
HRESULT hRes=ED.m_pDI->CreateDevice(lpddi->guidInstance,Dev.m_pDID,NULL);
if(FAILED(hRes))
{
throw JOY_EXCEPTION(hRes);
}
Dev.Update(ED.m_pCore->m_pDIJoyCfg);
Dev.m_bInitialized=true;
ED.m_pCore->m_ListDIDev.push_back(Dev);
}
catch(JoyException E)
{
}
catch(exception)
{
}
return DIENUM_CONTINUE;
}
BOOL CALLBACK DIEnumJoyTypePr(LPCWSTR pwszTypeName,LPVOID pvRef)
{
try
{
HRESULT hRes=S_OK;
String TN=pwszTypeName;
SEnumDev &ED=*(SEnumDev*)pvRef;
DIJOYTYPEINFO JoyInfo;
ZeroMemory(&JoyInfo,sizeof(JoyInfo));
JoyInfo.dwSize=sizeof(JoyInfo);
switch(ED.m_pCore->m_pDIJoyCfg->GetTypeInfo(pwszTypeName,&JoyInfo,DITC_REGHWSETTINGS))
{
//Errors to continue with.
case DIERR_NOTFOUND:
return DIENUM_CONTINUE;
//Errors to stop with.
case DIERR_INVALIDPARAM:
case DIERR_NOMOREITEMS:
return DIENUM_STOP;
}
if(JoyInfo.hws.dwFlags&JOY_HWS_ISGAMEPORTBUS)
{
CGprtDev D;
D.m_Name=TN;
ZeroMemory(&D.m_Info,sizeof(D.m_Info));
D.m_Info.dwSize=sizeof(D.m_Info);
DWORD dwFlags=DITC_CLSIDCONFIG|DITC_DISPLAYNAME;
if(FAILED(ED.m_pCore->m_pDIJoyCfg->GetTypeInfo(D.m_Name.data(),&D.m_Info,dwFlags)))
{
throw JOY_EXCEPTION(hRes);
}
ED.m_pCore->m_GprtBus.push_back(D);
}
else if(!(JoyInfo.hws.dwFlags&JOY_HWS_AUTOLOAD))
{
CGprtDev D;
D.m_Name=TN;
ZeroMemory(&D.m_Info,sizeof(D.m_Info));
D.m_Info.dwSize=sizeof(D.m_Info);
DWORD dwFlags=DITC_REGHWSETTINGS|DITC_FLAGS1|DITC_HARDWAREID|DITC_CALLOUT|DITC_DISPLAYNAME;
if(FAILED(ED.m_pCore->m_pDIJoyCfg->GetTypeInfo(D.m_Name.data(),&D.m_Info,dwFlags)))
{
throw JOY_EXCEPTION(hRes);
}
ED.m_pCore->m_GprtDev.push_back(D);
}
}
catch(JoyException E)
{
}
catch(exception)
{
}
return DIENUM_CONTINUE;
}
CCore::CCore()
{
m_bAccess=false;
m_bInitialized=false;
}
bool CCore::IsAutoDetectGprt()
{
if(!m_GprtDev.size())return false;
if(m_GprtDev.front().m_Info.dwFlags1&
JOYTYPE_NOAUTODETECTGAMEPORT)return false;
return true;
}
int CCore::GetNextAvailableId()
{
if(!m_bInitialized)return -1;
DIJOYCONFIG JoyCfg;
ZeroMemory(&JoyCfg,sizeof(JoyCfg));
JoyCfg.dwSize=sizeof(JoyCfg);
for(int i=0;i<NUMJOYDEVS;i++)
{
switch(m_pDIJoyCfg->GetConfig(i,&JoyCfg,DIJC_REGHWCONFIGTYPE))
{
case S_FALSE:
case DIERR_NOMOREITEMS:
case DIERR_NOTFOUND:
case E_FAIL:
return i;
}
}
return -1;
}
bool CCore::FullJoyOemAccess()
{
LONG lRc;
HKEY hk;
bool bRc;
lRc = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
REGSTR_PATH_JOYOEM,
0,
KEY_ALL_ACCESS & ~WRITE_DAC & ~WRITE_OWNER,
&hk);
if( lRc == ERROR_SUCCESS ) {
bRc = true;
RegCloseKey(hk);
} else {
bRc = false;
}
return bRc;
}
HRESULT CCore::AddDevice(LPCTSTR pTypeName,bool bRudder,LPCTSTR pGprtId,GUID &GOccupied)
{
HRESULT hRes=S_OK;
GOccupied=NULLGUID;
if(!m_bInitialized)return E_FAIL;
if(m_GprtDev.size()>=MAX_DEVICES)return E_FAIL;
LISTGPRTDEV::iterator It;
It=find(m_GprtDev.begin(),m_GprtDev.end(),pTypeName);
if(It==m_GprtDev.end())return E_FAIL;
CGprtDev *pGprtDev=&*It;
int nId=GetNextAvailableId();
if(nId==-1)return DIERR_NOTFOUND;
DIJOYCONFIG JoyCfg;
ZeroMemory(&JoyCfg,sizeof(JoyCfg));
JoyCfg.dwSize=sizeof(JoyCfg);
JoyCfg.hwc.hws=pGprtDev->m_Info.hws;
JoyCfg.hwc.hws.dwFlags|=JOY_HWS_ISANALOGPORTDRIVER;
if(bRudder)
{
JoyCfg.hwc.hws.dwFlags|=JOY_HWS_HASR;
JoyCfg.hwc.dwUsageSettings|=JOY_US_HASRUDDER;
}
JoyCfg.hwc.dwUsageSettings|=JOY_US_PRESENT;
//JoyCfg.hwc.dwType=nArrayID;WHY is this beeing set to index?????????????????????????????????????????????????????????????????????????????????
wcsncpy(JoyCfg.wszCallout,pGprtDev->m_Info.wszCallout,sizeof(JoyCfg.wszCallout)/sizeof(JoyCfg.wszCallout[0])-1);
wcsncpy(JoyCfg.wszType,pGprtDev->m_Name.data(),sizeof(JoyCfg.wszType)/sizeof(JoyCfg.wszType[0])-1);
if(SUCCEEDED(hRes=m_pDIJoyCfg->Acquire()))
{
if(m_GprtBus.size())
{
if(m_GprtBus.size()>1)
{
if(pGprtId)
{
String GId=pGprtId;
LISTGPRTDEV::iterator It;
It=find(m_GprtBus.begin(),m_GprtBus.end(),GId.data());
if(It!=m_GprtDev.end())
{
JoyCfg.guidGameport=It->m_Info.clsidConfig;
}
}
}
else
{
JoyCfg.guidGameport=m_GprtBus.front().m_Info.clsidConfig;
}
}
if(FAILED(hRes=m_pDIJoyCfg->SetConfig(nId,&JoyCfg,DIJC_REGHWCONFIGTYPE|DIJC_CALLOUT)))
{
m_pDIJoyCfg->Unacquire();
if(hRes==E_ACCESSDENIED)
GOccupied=JoyCfg.guidGameport;
return hRes;
}
else
{
//Fix #55524.
if(SUCCEEDED(m_pDIJoyCfg->GetConfig(nId,&JoyCfg,DIJC_REGHWCONFIGTYPE)))
{
if(!(JoyCfg.hwc.dwUsageSettings&JOY_US_PRESENT))
{
JoyCfg.hwc.dwUsageSettings|=JOY_US_PRESENT;
JoyCfg.hwc.hwv.dwCalFlags|=0x80000000;
JoyCfg.hwc.hws.dwFlags|=JOY_HWS_ISANALOGPORTDRIVER;
m_pDIJoyCfg->SetConfig(nId,&JoyCfg,DIJC_REGHWCONFIGTYPE);
}
}
//End of fix #55524.
}
m_pDIJoyCfg->Unacquire();
}
Update();
UpdateType();
return hRes;
}
void CCore::Initialize(HWND hWnd)
{
if((LPDIRECTINPUTJOYCONFIG8)m_pDIJoyCfg)
m_pDIJoyCfg->Release();
m_pDIJoyCfg=NULL;
if((LPDIRECTINPUT8)m_pDI)
m_pDI->Release();
m_pDI=NULL;
HMODULE hM=GetModuleHandle(NULL);
if(!hM)
{
throw JOY_EXCEPTION(E_FAIL);
}
HRESULT hRes=DirectInput8Create(hM,DIRECTINPUT_VERSION,
IID_IDirectInput8,(LPVOID*)&m_pDI,NULL);
if(FAILED(hRes))
{
throw JOY_EXCEPTION(hRes);
}
hRes=m_pDI->QueryInterface(IID_IDirectInputJoyConfig8,(LPVOID*)&m_pDIJoyCfg);
if(hRes!=DI_OK)
{
throw JOY_EXCEPTION(hRes);
}
hRes=m_pDIJoyCfg->SetCooperativeLevel(hWnd,DISCL_EXCLUSIVE|DISCL_BACKGROUND);
if(hRes!=DI_OK)
{
throw JOY_EXCEPTION(hRes);
}
m_bAccess = FullJoyOemAccess();
m_bInitialized=true;
}
void CCore::Update()
{
HRESULT hRes;
if(!m_bInitialized)
{
throw JOY_EXCEPTION(E_FAIL);
}
m_ListDIDev.clear();
SEnumDev ED(m_ListDIDev,m_pDI,this);
hRes=m_pDI->EnumDevices(DI8DEVCLASS_GAMECTRL,DIEnumDevicesProc,&ED,DIEDFL_ALLDEVICES);
if(FAILED(hRes))
{
//EnumDevices goes wrong
; //throw JOY_EXCEPTION(hRes);
}
UIUpdate();
}
void CCore::UpdateType()
{
if(!m_bInitialized)
{
throw JOY_EXCEPTION(E_FAIL);
}
m_GprtDrv.clear();
m_GprtBus.clear();
m_GprtDev.clear();
HRESULT hRes=S_OK;
SEnumDev ED(m_ListDIDev,m_pDI,this);
hRes=m_pDIJoyCfg->EnumTypes(DIEnumJoyTypePr,&ED);
if(FAILED(hRes))
{
throw JOY_EXCEPTION(hRes);
}
UIUpdate();
}
CDIDev *CCore::FindDIDev(GUID &Guid)
{
LISTDIDEV::iterator It;
It=find(m_ListDIDev.begin(),m_ListDIDev.end(),Guid);
if(It==m_ListDIDev.end())return NULL;
return &*It;
}
HRESULT CCore::Remove(GUID &Guid)
{
if(!m_bInitialized)
{
throw JOY_EXCEPTION(E_FAIL);
}
CDIDev *pDev=FindDIDev(Guid);
if(!pDev)return E_FAIL;
HRESULT hRes;
if(FAILED(hRes=m_pDIJoyCfg->Acquire()))return hRes;
if(FAILED(hRes=m_pDIJoyCfg->DeleteConfig(pDev->Id())))
{
m_pDIJoyCfg->Unacquire();
return hRes;
}
m_pDIJoyCfg->SendNotify();
m_pDIJoyCfg->Unacquire();
return S_OK;
}
#define DIJC_ALL DIJC_REGHWCONFIGTYPE|DIJC_CALLOUT|DIJC_WDMGAMEPORT|DIJC_GAIN|DIJC_GUIDINSTANCE
void CCore::Preferred(GUID &G)
{
if(!m_bInitialized)
{
throw JOY_EXCEPTION(E_FAIL);
}
//Set Id of preferred device to 0.
//Find Id of device to be set to 0.
CDIDev *pDev=FindDIDev(G);
if(!pDev)return;
int nId=pDev->Id();
if(nId==0)//Already preferred.
return;
if(SUCCEEDED(m_pDIJoyCfg->Acquire()))
{
//We could call SetConfig only once and DInput on NT or Whistler should
//swap Id-s of two devices. However, it will not work if gameport device
//is unplugged, so we still must swap by salling SetConfig twice.
DIJOYCONFIG OldId0;
ZeroMemory(&OldId0,sizeof(OldId0));
OldId0.dwSize=sizeof(OldId0);
bool bOldId0=true;
HRESULT hRes = m_pDIJoyCfg->GetConfig(0,&OldId0,DIJC_ALL);
if(hRes==DIERR_NOTFOUND||hRes==S_FALSE)
bOldId0=false;
DIJOYCONFIG NewId0;
ZeroMemory(&NewId0,sizeof(NewId0));
NewId0.dwSize=sizeof(NewId0);
bool bNewId0=true;
hRes=m_pDIJoyCfg->GetConfig(nId,&NewId0,DIJC_ALL);
if(hRes==DIERR_NOTFOUND||hRes==S_FALSE)
bNewId0=false;
if(bOldId0)
m_pDIJoyCfg->SetConfig(nId,&OldId0,DIJC_ALL);
else
//We must still delete because GetConfig could fail for other
//reasons than device with Id 0 not present.
m_pDIJoyCfg->DeleteConfig(0);
if(bNewId0)
m_pDIJoyCfg->SetConfig(0,&NewId0,DIJC_ALL);
m_pDIJoyCfg->SendNotify();
m_pDIJoyCfg->Unacquire();
}
Update();
}
//Partialy copied from old joy.cpl.
//I strongly suspect this is not documented anywhere.
bool CCore::IsAvailableVIDPID(String &VIDPIDName)
{
if(!m_bInitialized)
{
throw JOY_EXCEPTION(E_FAIL);
}
HRESULT hRes=m_pDIJoyCfg->Acquire();
if(FAILED(hRes))throw JOY_EXCEPTION(hRes);
//Make the VID/PID to compare from the following formula:
//VID_045e&PID_100+JOY_HW_LASTENTRY to 100+JOY_HW_LASTENTRY+0xf
TCHAR Type[18];
_tcsncpy(Type,_T("VID_045E&PID_0100"),18);
Type[17] = 0;
const WCHAR Lookup[]=_T("0123456789ABCDEF");
int i=JOY_HW_LASTENTRY;
do
{
if(i<0x10)
{
Type[16]=Lookup[i];
}
else
{
Type[15]=Lookup[1];
Type[16]=Lookup[i%0x10];
}
i++;
HKEY hKey;
if(FAILED(m_pDIJoyCfg->OpenTypeKey(Type,KEY_READ,&hKey)))
break;
RegCloseKey(hKey);
}
while(i<(JOY_HW_LASTENTRY+0x11));
m_pDIJoyCfg->Unacquire();
if(i<0x1d)
{
VIDPIDName=Type;
return true;
}
return false;
}
CGprtDev *CCore::FindGprtDev(LPCTSTR pTypeName)
{
if(!pTypeName)return NULL;
if(!m_bInitialized)
{
throw JOY_EXCEPTION(E_FAIL);
}
for(LISTGPRTDEV::iterator It=m_GprtDev.begin();
It!=m_GprtDev.end();It++)
{
if(It->m_Name==pTypeName)
return &(*It);
}
return NULL;
}
bool CCore::IsCustomDevice(LPCTSTR pTypeName)
{
if(!pTypeName)return false;
if(!m_bInitialized)
{
throw JOY_EXCEPTION(E_FAIL);
}
if(pTypeName[0]==_T('#'))return false;//Standard type.
CGprtDev *pDevType=FindGprtDev(pTypeName);
if(!pDevType)
//This should never happend, but just in case.
throw JOY_EXCEPTION(E_FAIL);
if(!pDevType->m_Info.wszHardwareId[0])
{
if(!pDevType->m_Info.wszCallout[0])
return true;
}
else
{
TCHAR AnalogRoot[]=_T("gameport\\vid_045e&pid_01");
//Test if it is predefined custom. Do not delete.
TCHAR C=pDevType->m_Info.wszHardwareId[(sizeof(AnalogRoot)/
sizeof(AnalogRoot[0]))-1];
if((C==_T('f'))||(C==_T('F')))
return false;
//Now test if it is custom.
if(!_tcsnicmp(pDevType->m_Info.wszHardwareId,AnalogRoot,
(sizeof(AnalogRoot)/sizeof(AnalogRoot[0]))-1))
return true;
}
return false;
}
void CCore::DeleteType(LPCTSTR pTypeName)
{
if(!pTypeName)return;
if(!m_bInitialized)
{
throw JOY_EXCEPTION(E_FAIL);
}
HRESULT hRes=m_pDIJoyCfg->Acquire();
if(FAILED(hRes))throw JOY_EXCEPTION(hRes);
m_pDIJoyCfg->DeleteType(pTypeName);
m_pDIJoyCfg->Unacquire();
UpdateType();
}
bool CCore::IsDeviceActive(LPCTSTR pTypeName)
{
if(!pTypeName)return false;
if(!m_bInitialized)
{
throw JOY_EXCEPTION(E_FAIL);
}
for(LISTDIDEV::iterator It=m_ListDIDev.begin();
It!=m_ListDIDev.end();It++)
{
DIJOYCONFIG JoyCfg;
ZeroMemory(&JoyCfg,sizeof(JoyCfg));
JoyCfg.dwSize=sizeof(JoyCfg);
if(SUCCEEDED(m_pDIJoyCfg->GetConfig(It->Id(),&JoyCfg,
DIJC_REGHWCONFIGTYPE)))
{
if(!_tcscmp(JoyCfg.wszType,pTypeName))
return true;
}
}
return false;
}
bool CCore::DuplicateDeviceName(LPCTSTR pName)
{
if(!m_bInitialized)
{
throw JOY_EXCEPTION(E_FAIL);
}
for(LISTGPRTDEV::iterator It=m_GprtDev.begin();
It!=m_GprtDev.end();It++)
{
if(!_tcsncmp(pName,It->Name(),
(sizeof(It->m_Info.wszDisplayName)/
sizeof(It->m_Info.wszDisplayName[0]))-1))
return true;
}
return false;
}
void CCore::AddCustomDevice(bool bJoy,bool bPad,bool bYoke,bool bCar,
int nAxes,bool bZAxis,int nButtons,bool bHasPov,LPCTSTR pName,
LPCTSTR pVIDPIDName)
{
if(!m_bInitialized)
{
throw JOY_EXCEPTION(E_FAIL);
}
String VIDPIDName=_T("GamePort\\");
VIDPIDName+=pVIDPIDName;
HRESULT hRes=m_pDIJoyCfg->Acquire();
if(FAILED(hRes))throw JOY_EXCEPTION(hRes);
DIJOYTYPEINFO JTI;
ZeroMemory(&JTI,sizeof(JTI));
JTI.dwSize=sizeof(JTI);
int nCh=sizeof(JTI.wszDisplayName)/
sizeof(JTI.wszDisplayName[0]);
_tcsncpy(JTI.wszDisplayName,pName,nCh);
JTI.wszDisplayName[nCh-1]=0;
JTI.hws.dwNumButtons=nButtons;
if(nAxes==3)
{
if(bZAxis)
JTI.hws.dwFlags|=JOY_HWS_HASZ;
else
JTI.hws.dwFlags|=JOY_HWS_HASR;
}
else if(nAxes==4)
{
JTI.hws.dwFlags|=JOY_HWS_HASR|JOY_HWS_HASZ;
}
if(bHasPov)
JTI.hws.dwFlags|=JOY_HWS_HASPOV|JOY_HWS_POVISBUTTONCOMBOS;
if(!bJoy)
{
if(bPad)
{
JTI.hws.dwFlags|=JOY_HWS_ISGAMEPAD;
}
else if(bCar)
{
JTI.hws.dwFlags|=JOY_HWS_ISCARCTRL;
}
else
{
JTI.hws.dwFlags|=JOY_HWS_ISYOKE;
}
}
nCh=sizeof(JTI.wszHardwareId)/
sizeof(JTI.wszHardwareId[0]);
_tcsncpy(JTI.wszHardwareId,VIDPIDName.data(),nCh);
JTI.wszDisplayName[nCh-1]=0;
hRes=m_pDIJoyCfg->SetTypeInfo(pVIDPIDName,&JTI,
DITC_DISPLAYNAME|DITC_CLSIDCONFIG|
DITC_REGHWSETTINGS|DITC_HARDWAREID,NULL);
m_pDIJoyCfg->Unacquire();
if(FAILED(hRes))throw JOY_EXCEPTION(hRes);
UpdateType();
}
/******************************************************************************
UI
******************************************************************************/
/******************************************************************************
UI header
******************************************************************************/
class CDlgProcHandler//this is not in CDlg because we want to reuse for property sheets...
{
protected:
HWND m_hWnd;
HMODULE m_hModule;
static INT_PTR CALLBACK DialogProc
(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam);
virtual INT_PTR DialogProc(UINT uMsg,WPARAM wParam,LPARAM lParam);
virtual BOOL InitDialog(HWND hFocus,LPARAM lParam){return TRUE;};
virtual BOOL Timer(WPARAM wTimerID){return FALSE;};
virtual INT_PTR Command(WORD wNotifyCode,WORD wID,HWND hwndCtl);
virtual INT_PTR Notify(int idCtrl,LPNMHDR pnmh){return 0;};
HWND HDlgItem(int nIDDlgItem){return GetDlgItem(m_hWnd,nIDDlgItem);};
public:
CDlgProcHandler(){m_hWnd=NULL;m_hModule=NULL;};
};
class CDlg:public CDlgProcHandler
{
protected:
virtual INT_PTR DialogProc(UINT uMsg,WPARAM wParam,LPARAM lParam);
virtual INT_PTR Command(WORD wNotifyCode,WORD wID,HWND hwndCtl);
public:
int Dlg(WORD wID,HMODULE hModule,HWND hParent);
};
int CDlg::Dlg(WORD wID,HMODULE hModule,HWND hParent)
{
m_hModule=hModule;
return DialogBoxParam(hModule,MAKEINTRESOURCE(wID),hParent,
CDlgProcHandler::DialogProc,(LPARAM)this);
}
typedef list<GUID> LISTGUID;
class CMainDlg;
class CPreferredDlg:public CDlg
{
LISTGUID m_ListCtrl;
bool m_bBlockUpdate;
CCore *m_pCore;
CMainDlg *m_pMainDlg;
virtual BOOL InitDialog(HWND hFocus,LPARAM lParam);
virtual INT_PTR Command(WORD wNotifyCode,WORD wID,HWND hwndCtl);
void Preferred();
INT_PTR Notify(int idCtrl,LPNMHDR pnmh);
public:
CPreferredDlg(CMainDlg *pMainDlg,CCore *pCore)
{m_pMainDlg=pMainDlg;m_pCore=pCore;m_bBlockUpdate=false;};
void Update();
};
class CAddDlg:public CDlg
{
CCore *m_pCore;
// CMainDlg *m_pMainDlg;
LISTSTRING m_ListCtrl;
LISTSTRING m_GprtListCtrl;
bool m_bBlockUpdate;
BOOL InitDialog(HWND hFocus,LPARAM lParam);
INT_PTR Command(WORD wNotifyCode,WORD wID,HWND hwndCtl);
void AddDev();
INT_PTR DialogProc(UINT uMsg,WPARAM wParam,LPARAM lParam);
public:
CAddDlg(/*CMainDlg *pMainDlg,*/CCore *pCore)
{/*m_pMainDlg=pMainDlg;*/m_pCore=pCore;m_bBlockUpdate=false;};
void Update();
};
class CCustomDlg:public CDlg
{
CCore *m_pCore;
String m_VIDPIDName;
BOOL InitDialog(HWND hFocus,LPARAM lParam);
INT_PTR Command(WORD wNotifyCode,WORD wID,HWND hwndCtl);
public:
CCustomDlg(CCore *pCore){m_pCore=pCore;};
LPCTSTR GetVIDPIDName(){return m_VIDPIDName.data();};
};
class CMainDlg:public CDlg
{
LISTGUID m_ListCtrl;
bool m_bBlockUpdate;
CCore *m_pCore;
CPreferredDlg *m_pPrefDlg;
CAddDlg *m_pAddDlg;
bool m_bEditingName;
virtual BOOL InitDialog(HWND hFocus,LPARAM lParam);
virtual BOOL Timer(WPARAM wTimerID);
virtual INT_PTR Command(WORD wNotifyCode,WORD wID,HWND hwndCtl);
INT_PTR DialogProc(UINT uMsg,WPARAM wParam,LPARAM lParam);
INT_PTR Notify(int idCtrl,LPNMHDR pnmh);
void Remove();
void Prop();
protected:
CMainDlg(){m_pCore=NULL;m_bBlockUpdate=false;m_pPrefDlg=NULL;m_pAddDlg=NULL;m_bEditingName=false;};
void ConnectUI(CCore *pCore){m_pCore=pCore;};
void Update();
void CoreUpdate();
};
class CUpdate
{
bool *m_pbBlockUpdate;
public:
CUpdate(bool *pbBlockUpdate)
{m_pbBlockUpdate=pbBlockUpdate;*m_pbBlockUpdate=true;};
~CUpdate(){*m_pbBlockUpdate=false;};
};
/******************************************************************************
End of UI header
******************************************************************************/
#define DEVICE_COLUMN 0
#define STATUS_COLUMN 1
LPTSTR Insert1String(LPCTSTR pS,LPCTSTR pI)
{
LPTSTR pR=new TCHAR[_tcslen(pS)+_tcslen(pI)+1];
wsprintf(pR,pS,pI);
return pR;
}
LPTSTR Insert2Strings(LPCTSTR pS,LPCTSTR pI1,LPCTSTR pI2)
{
LPTSTR pR=new TCHAR[_tcslen(pS)+_tcslen(pI1)+_tcslen(pI2)+1];
wsprintf(pR,pS,pI1,pI2);
return pR;
}
void MessageBox(HWND hWnd,HINSTANCE hInstance,UINT uTitleID,UINT uMsgID)
{
TCHAR Title[128];
TCHAR Msg[256];
LoadString(hInstance,uTitleID, Title, cA(Title));
LoadString(hInstance,uMsgID, Msg, cA(Msg));
UINT uRTL = (GetWindowLongPtr(hWnd,GWL_EXSTYLE) & WS_EX_LAYOUTRTL) ? MB_RTLREADING : 0;
MessageBox(hWnd,Msg,Title,MB_ICONHAND|MB_OK|MB_APPLMODAL|uRTL);
}
void LVSetItem(HWND hCtrl,int nItem,int nSubItem, LPCTSTR lpStr)
{
LVITEM Item;
ZeroMemory(&Item,sizeof(Item));
Item.mask=LVIF_TEXT;
Item.iItem=nItem;
Item.iSubItem=nSubItem;
Item.cchTextMax=lstrlen(lpStr);
Item.pszText=(LPTSTR)lpStr;
SendMessage(hCtrl,LVM_SETITEM,0,(LPARAM)(const LPLVITEM)&Item);
}
void LVInsertItem(HWND hCtrl,int nItem,int nSubItem,LPCTSTR lpStr,LPARAM lData)
{
LVITEM Item;
ZeroMemory(&Item,sizeof(Item));
Item.mask=LVIF_TEXT|LVIF_PARAM;
Item.iItem=nItem;
Item.cchTextMax=lstrlen(lpStr);
Item.pszText=(LPTSTR)lpStr;
Item.lParam=lData;
SendMessage(hCtrl,LVM_INSERTITEM,0,(LPARAM)(const LPLVITEM)&Item);
}
void *LVGetItemDataPtr(HWND hCtrl,int nItem)
{
LVITEM Item;
ZeroMemory(&Item,sizeof(LVITEM));
Item.mask=LVIF_PARAM;
Item.iItem=nItem;
if(SendMessage(hCtrl,LVM_GETITEM,0,(LPARAM)(LPLVITEM)&Item))
return(void*)Item.lParam;
return NULL;
}
const GUID &LVGetItemGUID(HWND hCtrl,int nItem)
{
if(nItem<0)return NULLGUID;
GUID *pG=(GUID*)LVGetItemDataPtr(hCtrl,nItem);
if(pG)return *pG;
return NULLGUID;
}
int LVFindGUIDIndex(HWND hCtrl,GUID &G)
{
int nCnt=ListView_GetItemCount(hCtrl);
for(int i=0;i<nCnt;i++)
if(G==LVGetItemGUID(hCtrl,i))return i;
return -1;
}
int LVGetSel(HWND hCtrl)
{
return ListView_GetNextItem(hCtrl,-1,LVNI_SELECTED);
}
void LVSetSel(HWND hCtrl,int nItem,bool bSel=true)
{
if(bSel)
ListView_SetItemState(hCtrl,nItem,
LVIS_FOCUSED|LVIS_SELECTED,0x000F)
else
ListView_SetItemState(hCtrl,nItem,
0,0x000F);
}
void LVInsertColumn (HWND hCtrl,int nColumn,UINT uID,int nWidth,HINSTANCE hInstance)
{
LVCOLUMN Col;
ZeroMemory(&Col,sizeof(Col));
Col.mask=LVCF_FMT|LVCF_TEXT|LVCF_WIDTH;
Col.fmt=LVCFMT_CENTER;
Col.cx=nWidth;
TCHAR S[128];
LoadString(hInstance,uID, S, cA(S));
Col.pszText=(LPTSTR)S;
SendMessage(hCtrl,LVM_INSERTCOLUMN,(WPARAM)(int)nColumn,(LPARAM)(const LPLVCOLUMN)&Col);
}
INT_PTR CDlgProcHandler::DialogProc(UINT uMsg,WPARAM wParam,LPARAM lParam)
{
switch(uMsg)
{
case WM_INITDIALOG:
return InitDialog((HWND)wParam,lParam);
case WM_TIMER:
return Timer(wParam);
case WM_COMMAND:
return Command(HIWORD(wParam),LOWORD(wParam),(HWND)lParam);
case WM_NOTIFY:
return Notify((int)wParam,(LPNMHDR)lParam);
case WM_CONTEXTMENU:
{
TCHAR HelpFileName[128];
LoadString(m_hModule,IDS_HELPFILENAME, HelpFileName, cA(HelpFileName));
WinHelp((HWND)wParam,HelpFileName,HELP_CONTEXTMENU,(ULONG_PTR)gaHelpIDs);
}
//Undocumented in msdn but otherwise
//problem rightclicking title to close.
return TRUE;
default:
return FALSE;
}
return FALSE;
}
INT_PTR CDlgProcHandler::Command(WORD wNotifyCode,WORD wID,HWND hwndCtl)
{
switch(wID)
{
case IDC_WHATSTHIS:
{
TCHAR HelpFileName[128];
LoadString(m_hModule,IDS_HELPFILENAME, HelpFileName, cA(HelpFileName));
WinHelp(hwndCtl,HelpFileName,HELP_WM_HELP,(ULONG_PTR)gaHelpIDs);
}
return 0;
}
return 0;
};
INT_PTR CALLBACK CDlgProcHandler::DialogProc
(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
CDlgProcHandler* pH=NULL;
try
{
if(uMsg==WM_INITDIALOG)
{
SetLastError(0);
LONG lRet=SetWindowLongPtr(hwndDlg,GWLP_USERDATA,lParam);
if(GetLastError()&&!lRet) {
EndDialog(hwndDlg,E_FAIL);
}
}
pH=(CDlgProcHandler*)GetWindowLongPtr(hwndDlg,GWLP_USERDATA);
if(pH && !IsBadReadPtr(pH, sizeof(CDlgProcHandler)))
{
if(uMsg==WM_INITDIALOG) {
pH->m_hWnd=hwndDlg;
}
if( pH->m_hWnd == hwndDlg ) {
return pH->DialogProc(uMsg,wParam,lParam);
}
}
return FALSE;
}
catch(JoyException E)
{
if(pH)
{
if(uMsg==WM_INITDIALOG) {
EndDialog(pH->m_hWnd,IDCANCEL);
}
}
}
catch(...)
{
if(pH && !IsBadReadPtr(pH, sizeof(CDlgProcHandler))) {
EndDialog(pH->m_hWnd, IDCANCEL);
}
//should report error here, and keep going.
}
if(uMsg==WM_INITDIALOG) {
return TRUE;
}
return FALSE;
}
/******************************************************************************
CDlg
******************************************************************************/
INT_PTR CDlg::Command(WORD wNotifyCode,WORD wID,HWND hwndCtl)
{
switch(wID)
{
case IDOK:
if(!(wNotifyCode&~1))
EndDialog(m_hWnd,IDOK);
return 0;
case IDCANCEL:
if(!(wNotifyCode&~1))
EndDialog(m_hWnd,IDCANCEL);
return 0;
}
return CDlgProcHandler::Command(wNotifyCode,wID,hwndCtl);
};
INT_PTR CDlg::DialogProc(UINT uMsg,WPARAM wParam,LPARAM lParam)
{
switch(uMsg)
{
case WM_CLOSE:
EndDialog(m_hWnd,0);
return 0;
}
return CDlgProcHandler::DialogProc(uMsg,wParam,lParam);
}
/******************************************************************************
Main dialog CMainDlg
******************************************************************************/
void CMainDlg::Remove()
{
{
if(!m_pCore->Access())
{
MessageBox(m_hWnd,m_hModule,IDS_USER_MODE_TITLE,IDS_USER_MODE);
return;
}
HWND hListCtrl=HDlgItem(IDC_LIST_DEVICE);
if(hListCtrl)
{
int nSelDev=LVGetSel(hListCtrl);
if(nSelDev<0)return;
GUID G=LVGetItemGUID(hListCtrl,nSelDev);
CDIDev *pDev=m_pCore->FindDIDev(G);
if(!pDev) {
return;
}
TCHAR AreSure[256];
LoadString(m_hModule,IDS_GEN_AREYOUSURE, AreSure, cA(AreSure));
LPTSTR pT = Insert1String(AreSure,pDev->InstName());
lstrcpy(AreSure, pT);
delete[] pT;
TCHAR Title[128];
LoadString(m_hModule,IDS_GEN_AREYOUSURE_TITLE, Title, cA(Title));
UINT uRTL = (GetWindowLongPtr(m_hWnd,GWL_EXSTYLE) & WS_EX_LAYOUTRTL) ? MB_RTLREADING : 0;
if(IDYES!=MessageBox(m_hWnd,AreSure,Title,MB_ICONQUESTION|MB_YESNO|MB_APPLMODAL|uRTL)) {
return;
}
if(m_pCore->Remove(G)==DIERR_UNSUPPORTED) {
MessageBox(m_hWnd,m_hModule,IDS_GEN_AREYOUSURE_TITLE,IDS_GEN_NO_REMOVE_USB);
}
}
}
CoreUpdate();
}
void OnHelp(LPHELPINFO pHelpInfo,HINSTANCE hInstance)
{
TCHAR FileName[256];
LoadString(hInstance,IDS_HELPFILENAME, FileName, cA(FileName));
if(pHelpInfo->iContextType==HELPINFO_WINDOW)
WinHelp((HWND)pHelpInfo->hItemHandle,FileName,HELP_WM_HELP,(ULONG_PTR)gaHelpIDs);
}
INT_PTR CMainDlg::DialogProc(UINT uMsg,WPARAM wParam,LPARAM lParam)
{
switch(uMsg)
{
case WM_ACTIVATEAPP:
CoreUpdate();
return 0;
/* case WM_POWERBROADCAST:
switch( wParam )
{
return 0;
case PBT_APMSUSPEND:
// Suspend operation!
KillTimer(hDlg, ID_MYTIMER);
break;
case PBT_APMRESUMESUSPEND:
case PBT_APMRESUMECRITICAL:
// Resume operation!
SetActive(hDlg);
break;
}
break;return 0;*/
case WM_DEVICECHANGE:
CoreUpdate();
return 0;
case WM_HELP:
OnHelp((LPHELPINFO)lParam,m_hModule);
return 0;
/* nFlags &= ~ON_PAGE;
KillTimer(hDlg, ID_MYTIMER);
OnContextMenu(wParam, lParam);
nFlags |= ON_PAGE;
SetTimer(hDlg, ID_MYTIMER, POLLRATE, 0);
return(1); return 0;???
*/
case WM_SYSCOLORCHANGE:
{
HWND hListCtrl=HDlgItem(IDC_LIST_DEVICE);
if(hListCtrl)
{
SendMessage(hListCtrl,WM_SYSCOLORCHANGE,0,0);
}
}
return 0;
}
return CDlg::DialogProc(uMsg,wParam,lParam);
}
void CMainDlg::Prop()
{
HWND hListCtrl=HDlgItem(IDC_LIST_DEVICE);
if(hListCtrl)
{
int nSelDev=LVGetSel(hListCtrl);
if(nSelDev<0)return;
GUID G=LVGetItemGUID(hListCtrl,nSelDev);
CDIDev *pDev=m_pCore->FindDIDev(G);
//ISSUE-2001/03/29-timgill internal error;SHOULD ASSERT HERE
if(!pDev)return;
//need to kill the timer before launching property sheet - see Whistler bug 260145 for details
KillTimer(m_hWnd,1);
switch(Properties(m_hModule,m_hWnd,m_pCore,pDev->Id()))
{
case E_NOINTERFACE:
MessageBox(m_hWnd,m_hModule,IDS_INTERNAL_ERROR,IDS_NO_DIJOYCONFIG);
break;
default://Not handled for now or ever?
break;
};
//now update and re-set the timer
m_pCore->Update();
SetTimer(m_hWnd,1,5000,NULL);
}
}
INT_PTR CMainDlg::Command(WORD wNotifyCode,WORD wID,HWND hwndCtl)
{
switch(wID)
{
case IDC_BTN_ADV:
if(!m_pCore->Access()) {
MessageBox(m_hWnd,m_hModule,IDS_USER_MODE_TITLE,IDS_USER_MODE);
} else {
if(!m_pPrefDlg)
{
CPreferredDlg PrefDlg(this,m_pCore);
m_pPrefDlg=&PrefDlg;
PrefDlg.Dlg(IDD_ADV_CHANGE,m_hModule,m_hWnd);
m_pPrefDlg=NULL;
}
}
return 0;
case IDC_BTN_REMOVE:
Remove();
return 0;
case IDC_BTN_ADD:
if(!m_pCore->Access()) {
MessageBox(m_hWnd,m_hModule,IDS_USER_MODE_TITLE,IDS_USER_MODE);
} else {
if(!m_pAddDlg)
{
CAddDlg AddDlg(m_pCore);
m_pAddDlg=&AddDlg;
AddDlg.Dlg(IDD_ADD,m_hModule,m_hWnd);
m_pAddDlg=NULL;
}
}
return 0;
case IDC_BTN_TSHOOT:
{
TCHAR ExeBuff[MAX_PATH];
if( GetWindowsDirectory(ExeBuff,MAX_PATH) ) {
TCHAR CmdBuff[256];
LoadString(m_hModule,IDS_TSHOOT_CMD, CmdBuff, cA(CmdBuff));
STARTUPINFO Si;
PROCESS_INFORMATION Pi;
ZeroMemory(&Si,sizeof(Si));
ZeroMemory(&Pi,sizeof(Pi));
Si.cb=sizeof(Si);
// ISSUE-2000/12/20-MarcAnd Quick Fix to use HSS
// In other places where HSS is used, STARTF_FORCEONFEEDBACK is not set
// Changed IDS_TSHOOT_CMD from: "hh.exe joy.chm"
// to "explorer.exe hcp://help/tshoot/tsInputDev.htm"
// Need to make this OS specific to allow backprop to Win2k (or further)
Si.dwFlags=STARTF_USESHOWWINDOW|STARTF_FORCEONFEEDBACK;
Si.wShowWindow=SW_NORMAL;
ExeBuff[MAX_PATH-1]=0;
String Exe=ExeBuff;
String Cmd=CmdBuff;
if(Exe[Exe.size()-1]!=_T('\\'))
{
Exe+=_T('\\');
}
Exe+=_T("explorer.exe");
Cmd=_T("\"")+Exe+_T("\"")+_T(" ")+Cmd;
if(CreateProcess(Exe.data(),(LPTSTR)Cmd.data(),0,0,0,0,0,0,&Si,&Pi))
{
CloseHandle(Pi.hThread);
CloseHandle(Pi.hProcess);
}
} else {
// something is wrong when calling GetWindowsDirectory
;
}
}
return 0;
case IDC_BTN_PROPERTIES:
Prop();
return 0;
}
return CDlg::Command(wNotifyCode,wID,hwndCtl);
};
INT_PTR CMainDlg::Notify(int idCtrl,LPNMHDR pnmh)
{
switch(pnmh->code )
{
/* Keeping this just in case someone changes his/her mind soon.
case LVN_BEGINLABELEDIT:
{
HWND hListCtrl=HDlgItem(IDC_LIST_DEVICE);
if(!hListCtrl)return TRUE;
if(!m_pCore->Access())return TRUE;
PostMessage((HWND)::SendMessage(hListCtrl,LVM_GETEDITCONTROL,0,0),EM_SETLIMITTEXT,MAX_PATH-1,0);
m_bEditingName=true;
return(FALSE);
}
case LVN_ENDLABELEDIT:
{
m_bEditingName=false;
HWND hListCtrl=HDlgItem(IDC_LIST_DEVICE);
if(!hListCtrl)
{
CoreUpdate();
return FALSE;
}
HWND hCtrl=(HWND)SendMessage(hListCtrl,LVM_GETEDITCONTROL,0,0);
if(hCtrl)
{
if(SendMessage(hCtrl,EM_GETMODIFY,0,0))
{
int nLen=lstrlen(((NMLVDISPINFO*)pnmh)->item.pszText);
if((nLen>(MAX_PATH-1))||(nLen==0))
MessageBeep(MB_ICONHAND);
//Make sure the name is usable.
else if(_tcschr(((NMLVDISPINFO*)pnmh)->item.pszText,TEXT('\\')))
MessageBox(m_hWnd,m_hModule,IDS_INVALID_NAME_TITLE,IDS_INVALID_NAME);
else
{
int nSelDev=LVGetSel(hListCtrl);
GUID SelGUID=LVGetItemGUID(hListCtrl,nSelDev);
CDIDev *pSelDev=m_pCore->FindDIDev(SelGUID);
if(SUCCEEDED(pSelDev->Rename(((NMLVDISPINFO *)pnmh)->item.pszText)))
{
CoreUpdate();
return TRUE;
}
else
{
MessageBox(m_hWnd,m_hModule,IDS_NO_RENAME_TITLE,IDS_NO_RENAME);
}
}
}
}
CoreUpdate();
return FALSE;
}*/
case LVN_KEYDOWN:
switch(((LV_KEYDOWN*)pnmh)->wVKey)
{
case VK_DELETE:
Remove();
return 0;
case VK_F5:
CoreUpdate();
return 0;
}
return 0;
case LVN_ITEMCHANGED:
if(!(((LPNMLISTVIEW)pnmh)->uOldState&LVIS_SELECTED)&&
(((LPNMLISTVIEW)pnmh)->uNewState&LVIS_SELECTED)&&
(((LPNMLISTVIEW)pnmh)->uChanged&LVIF_STATE))
Update();
return 0;
case NM_DBLCLK:
switch(idCtrl)
{
case IDC_LIST_DEVICE:
Prop();
return 0;
}
return 0;
}
return 0;
}
void CMainDlg::CoreUpdate()
{
m_pCore->Update();
//KillTimer so if UI is updated for some other reason than WM_TIMER timer will be reset.
//make sure nothing can fail between KillTimer and SetTimer.
KillTimer(m_hWnd,1);
SetTimer(m_hWnd,1,5000,NULL);
}
BOOL CMainDlg::InitDialog(HWND hFocus,LPARAM lParam)
{
SetTimer(m_hWnd,1,5000,NULL);
m_pCore->Initialize(m_hWnd);
//#wi315410. we need to decide...
// m_pCore->UpdateType();
HWND hListCtrl=HDlgItem(IDC_LIST_DEVICE);
if(hListCtrl)
{
SendMessage(hListCtrl,LVM_SETEXTENDEDLISTVIEWSTYLE,0,LVS_EX_FULLROWSELECT);
RECT R;
GetClientRect(hListCtrl,&R);
int nWidth=(R.right>>2)*3;
LVInsertColumn(hListCtrl,DEVICE_COLUMN,IDS_GEN_DEVICE_HEADING,nWidth,m_hModule);
LVInsertColumn(hListCtrl,STATUS_COLUMN,IDS_GEN_STATUS_HEADING,R.right-nWidth,m_hModule);
}
CoreUpdate();
return TRUE;
}
BOOL CMainDlg::Timer(WPARAM wTimerID)
{
CoreUpdate();
return FALSE;
}
void CMainDlg::Update()
{
if(m_pPrefDlg)m_pPrefDlg->Update();
if(m_bEditingName)return;//Do not update this dialog when editing name.
if(m_bBlockUpdate)return;//Some actions may send notify messages which then Update and overflow stack.
CUpdate U(&m_bBlockUpdate);
int nSelDev=-1;
GUID SelGUID=NULLGUID;
HWND hListCtrl=HDlgItem(IDC_LIST_DEVICE);
if(hListCtrl)
{
nSelDev=LVGetSel(hListCtrl);
SelGUID=LVGetItemGUID(hListCtrl,nSelDev);
SendMessage(hListCtrl,WM_SETREDRAW,(WPARAM)FALSE,0);
SendMessage(hListCtrl,LVM_DELETEALLITEMS,0,0);
m_ListCtrl.clear();//Must be behind LVM_DELETEALLITEMS
int nIndex=0;
for(LISTDIDEV::iterator It=m_pCore->m_ListDIDev.begin();
It!=m_pCore->m_ListDIDev.end();It++)
{
GUID G=It->InstGUID();
m_ListCtrl.push_back(G);
LVInsertItem(hListCtrl,nIndex,DEVICE_COLUMN,
It->InstName(),(LPARAM)&m_ListCtrl.back());
TCHAR Status[256];
if(It->Status()==ENotConnected) {
LoadString(m_hModule,IDS_GEN_STATUS_NOTCONNECTED, Status, cA(Status));
} else if(It->Status()==EConnected) {
LoadString(m_hModule,IDS_GEN_STATUS_OK, Status, cA(Status));
} else {
LoadString(m_hModule,IDS_GEN_STATUS_UNKNOWN, Status, cA(Status));
}
LVSetItem(hListCtrl,nIndex,STATUS_COLUMN,Status);
nIndex++;
}
nSelDev=LVFindGUIDIndex(hListCtrl,SelGUID);
if(nSelDev>=0)
{
LVSetSel(hListCtrl,nSelDev);
}
else
LVSetSel(hListCtrl,0);
nSelDev=LVGetSel(hListCtrl);
SendMessage(hListCtrl,WM_SETREDRAW,(WPARAM)TRUE,0);
InvalidateRect(hListCtrl,NULL,TRUE);
SelGUID=LVGetItemGUID(hListCtrl,nSelDev);
}
CDIDev *pSelDev=m_pCore->FindDIDev(SelGUID);
//#wi315410. we need to decide...
// HWND hAddBtn=HDlgItem(IDC_BTN_ADD);
// if(hAddBtn)
// {
// BOOL bE=(m_pCore->m_GprtBus.size()>0)?TRUE:FALSE;
// EnableWindow(hAddBtn,bE);
// }
HWND hRemBtn=HDlgItem(IDC_BTN_REMOVE);
if(hRemBtn)
{
BOOL bE=(nSelDev>=0)?TRUE:FALSE;
EnableWindow(hRemBtn,bE);
}
HWND hPropBtn=HDlgItem(IDC_BTN_PROPERTIES);
if(hPropBtn)
{
BOOL bE=FALSE;
if((nSelDev>=0)&&pSelDev)
if(pSelDev->Status()==EConnected)
bE=TRUE;
EnableWindow(hPropBtn,bE);
}
}
/******************************************************************************
Add dialog
******************************************************************************/
int CBGetCurSel(HWND hCtrl)
{
int i=ComboBox_GetCurSel(hCtrl);
if(i==CB_ERR)
i=-1;
return i;
}
int CBGetCnt(HWND hCtrl)
{
int i=ComboBox_GetCount(hCtrl);
if(i==CB_ERR)
i=0;
return i;
}
const GUID &CBGetItemGUID(HWND hCtrl,int iIndex)
{
LRESULT p=ComboBox_GetItemData(hCtrl,iIndex);
if(p==CB_ERR)return NULLGUID;
if(p)
return *(GUID*)p;
return NULLGUID;
}
int CBFindGUIDIndex(HWND hCtrl,const GUID &G)
{
int nCnt=ComboBox_GetCount(hCtrl);
if(nCnt==CB_ERR)return -1;
for(int i=0;i<nCnt;i++)
{
if(CBGetItemGUID(hCtrl,i)==G)
return i;
}
return -1;
}
LPCTSTR CBGetItemTypeName(HWND hCtrl,int iIndex)
{
LRESULT p=ComboBox_GetItemData(hCtrl,iIndex);
if(p==CB_ERR)return NULL;
if(p)
return ((String*)p)->data();
return NULL;
}
int CBFindTypeNameIndex(HWND hCtrl,LPCTSTR pTypeName)
{
int nCnt=ComboBox_GetCount(hCtrl);
if(nCnt==CB_ERR)return -1;
String TN;
if(pTypeName)
TN=pTypeName;
for(int i=0;i<nCnt;i++)
{
if(CBGetItemTypeName(hCtrl,i)==TN)
return i;
}
return -1;
}
int LBGetCurSel(HWND hCtrl)
{
int i=ListBox_GetCurSel(hCtrl);
if(i==LB_ERR)return -1;
return i;
}
LPCTSTR LBGetItemTypeName(HWND hCtrl,int iIndex)
{
LRESULT p=ListBox_GetItemData(hCtrl,iIndex);
if(p==LB_ERR)return NULL;
if(p)
return ((String*)p)->data();
return NULL;
}
int LBFindTypeNameIndex(HWND hCtrl,LPCTSTR pTypeName)
{
int nCnt=ListBox_GetCount(hCtrl);
if(nCnt==LB_ERR)return -1;
String TN;
if(pTypeName)
TN=pTypeName;
for(int i=0;i<nCnt;i++)
{
if(LBGetItemTypeName(hCtrl,i)==TN)
return i;
}
return -1;
}
BOOL CAddDlg::InitDialog(HWND hFocus,LPARAM lParam)
{
m_pCore->UpdateType();
Update();
return TRUE;
}
void CAddDlg::Update()
{
if(m_bBlockUpdate)return;//Some actions may send notify messages which then Update and overflow stack.
CUpdate U(&m_bBlockUpdate);
if(!m_hWnd)return;
//Update device list.
int nSelDev=-1;
String TypeName;
HWND hListCtrl=HDlgItem(IDC_DEVICE_LIST);
if(hListCtrl)
{
int nTopIndex=ListBox_GetTopIndex(hListCtrl);
nSelDev=LBGetCurSel(hListCtrl);
LPCTSTR pTypeName=LBGetItemTypeName(hListCtrl,nSelDev);
if(pTypeName)TypeName=pTypeName;
SetWindowRedraw(hListCtrl,FALSE);
ListBox_ResetContent(hListCtrl);
m_ListCtrl.clear();//Must be behind ListBox_ResetContent
for(LISTGPRTDEV::iterator It=m_pCore->m_GprtDev.begin();
It!=m_pCore->m_GprtDev.end();It++)
{
String S=It->TypeName();
m_ListCtrl.push_back(S);
int nIndex=ListBox_AddString(hListCtrl,It->Name());
ListBox_SetItemData(hListCtrl,nIndex,&m_ListCtrl.back());
}
nSelDev=LBFindTypeNameIndex(hListCtrl,TypeName.data());
if(nSelDev>=0)
ListBox_SetCurSel(hListCtrl,nSelDev);
else
ListBox_SetCurSel(hListCtrl,0);
ListBox_SetTopIndex(hListCtrl,nTopIndex);
SetWindowRedraw(hListCtrl,TRUE);
InvalidateRect(hListCtrl,NULL,TRUE);
nSelDev=LBGetCurSel(hListCtrl);
}
HWND hRudder=HDlgItem(IDC_JOY1HASRUDDER);
if(hRudder)
{
BOOL bE=FALSE;
if(nSelDev>=0)
{
LPCTSTR pTypeName=LBGetItemTypeName(hListCtrl,nSelDev);
if(pTypeName)
{
LISTGPRTDEV::iterator It;
It=find(m_pCore->m_GprtDev.begin(),m_pCore->m_GprtDev.end(),pTypeName);
if(It!=m_pCore->m_GprtDev.end())
bE=It->Rudder()?FALSE:TRUE;
}
}
EnableWindow(hRudder,bE);
}
//Update gameport list.
nSelDev=-1;
TypeName;
HWND hListCtrlTitle=HDlgItem(IDC_GAMEPORT);
hListCtrl=HDlgItem(IDC_GAMEPORTLIST);
if(hListCtrl&&hListCtrlTitle)
{
SetWindowRedraw(hListCtrl,FALSE);
SetWindowPos(hListCtrl,NULL,NULL,NULL,NULL,NULL,
SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_HIDEWINDOW);
//How many gameports. Gameport list only if more than 1.
if(m_pCore->m_GprtBus.size()>1)
{
ShowWindow(hListCtrlTitle,SW_SHOWNA);
nSelDev=CBGetCurSel(hListCtrl);
LPCTSTR pTypeName=CBGetItemTypeName(hListCtrl,nSelDev);
if(pTypeName)TypeName=pTypeName;
ComboBox_ResetContent(hListCtrl);
m_GprtListCtrl.clear();//Must be behind ComboBox_ResetContent
for(LISTGPRTDEV::iterator It=m_pCore->m_GprtBus.begin();
It!=m_pCore->m_GprtBus.end();It++)
{
String S=It->TypeName();
m_GprtListCtrl.push_back(S);
int nIndex=ComboBox_AddString(hListCtrl,It->Name());
ComboBox_SetItemData(hListCtrl,nIndex,&m_GprtListCtrl.back());
}
nSelDev=CBFindTypeNameIndex(hListCtrl,TypeName.data());
if(nSelDev>=0)
ComboBox_SetCurSel(hListCtrl,nSelDev);
else
ComboBox_SetCurSel(hListCtrl,0);
SetWindowPos(hListCtrl,NULL,NULL,NULL,NULL,NULL,
SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_SHOWWINDOW);
}
else
{
ShowWindow(hListCtrlTitle,SW_HIDE);
}
SetWindowRedraw(hListCtrl,TRUE);
InvalidateRect(hListCtrl,NULL,TRUE);
}
HWND hCustomBtn=HDlgItem(IDC_CUSTOM);
if(hCustomBtn)
{
BOOL bE=(m_pCore->m_GprtDev.size()<MAX_DEVICES)?TRUE:FALSE;
EnableWindow(hCustomBtn,bE);
}
}
void CAddDlg::AddDev()
{
HWND hListCtrl=HDlgItem(IDC_DEVICE_LIST);
HWND hRudder=HDlgItem(IDC_JOY1HASRUDDER);
if(hListCtrl&&hRudder)
{
int nSelDev=LBGetCurSel(hListCtrl);
LPCTSTR pTypeName=LBGetItemTypeName(hListCtrl,nSelDev);
HWND hListCtrlGprt=HDlgItem(IDC_GAMEPORTLIST);
nSelDev=CBGetCurSel(hListCtrlGprt);
LPCTSTR pGprtTypeName=CBGetItemTypeName(hListCtrlGprt,nSelDev);
if(!pGprtTypeName)
{
pGprtTypeName=m_pCore->m_GprtBus.front().TypeName();
}
if(pTypeName&&pGprtTypeName)
{
GUID GOccupied=NULLGUID;
HRESULT hRes=m_pCore->AddDevice(pTypeName,Button_GetCheck(hRudder)?true:false,pGprtTypeName,GOccupied);
if(!SUCCEEDED(hRes))
switch(hRes)
{
case E_FAIL:
break;
case E_ACCESSDENIED:
if(GOccupied!=NULLGUID)
{
//Find device which occupies the port.
for(LISTDIDEV::iterator It=m_pCore->m_ListDIDev.begin();It!=m_pCore->m_ListDIDev.end();It++)
{
if(It->PortGUID()==GOccupied)
{
TCHAR Title[128];
LoadString(m_hModule,IDS_ADD_PORT_OCCUPIED, Title, cA(Title));
TCHAR Msg[256];
LoadString(m_hModule,IDS_ADD_PORT_MSGFORMAT, Msg, cA(Msg));
//Get gameport name.
LPCTSTR pBus=_T(" ");
LISTGPRTDEV::iterator It;
It=find(m_pCore->m_GprtBus.begin(),m_pCore->m_GprtBus.end(),pGprtTypeName);
if(It!=m_pCore->m_GprtBus.end())
pBus=It->Name();
//Get device name.
LPCTSTR pDev=_T(" ");
LISTDIDEV::iterator ItDN;
for(ItDN=m_pCore->m_ListDIDev.begin();ItDN!=m_pCore->m_ListDIDev.end();ItDN++)
if(ItDN->PortGUID()==GOccupied)break;
if(ItDN!=m_pCore->m_ListDIDev.end())
pDev=ItDN->InstName();
LPTSTR pT = Insert2Strings(Msg,pDev,pBus);
lstrcpy(Msg, pT);
delete[] pT;
UINT uRTL = (GetWindowLongPtr(m_hWnd,GWL_EXSTYLE) & WS_EX_LAYOUTRTL) ? MB_RTLREADING : 0;
MessageBox(m_hWnd,Msg,Title,MB_ICONHAND|MB_OK|MB_APPLMODAL|uRTL);
break;
}
}
}
break;
case DIERR_DEVICEFULL:
MessageBox(m_hWnd,m_hModule,IDS_GAMEPORT_OCCUPIED_TITLE,IDS_GAMEPORT_OCCUPIED);
break;
case DIERR_NOTFOUND:
MessageBox(m_hWnd,m_hModule,IDS_NO_IDS_TITLE,IDS_NO_IDS);
break;
case DIERR_DEVICENOTREG:
MessageBox(m_hWnd,m_hModule,IDS_NO_GAMENUM_TITLE,IDS_NO_GAMENUM);
break;
}
}
}
EndDialog(m_hWnd,IDOK);
}
INT_PTR CAddDlg::Command(WORD wNotifyCode,WORD wID,HWND hwndCtl)
{
switch(wID)
{
case IDOK:
AddDev();
return 0;
case IDC_CUSTOM:
{
CCustomDlg CustomDlg(m_pCore);
if(CustomDlg.Dlg(IDD_CUSTOM,m_hModule,m_hWnd)==IDOK)
{
Update();
//Now select new custom device in this dialog box.
HWND hListCtrl=HDlgItem(IDC_DEVICE_LIST);
if(hListCtrl)
{
int nSelDev=LBFindTypeNameIndex(hListCtrl,CustomDlg.GetVIDPIDName());
if(nSelDev>=0)
{
ListBox_SetCurSel(hListCtrl,nSelDev);
}
}
}
}
return 0;
case IDC_DEVICE_LIST:
switch(wNotifyCode)
{
case LBN_DBLCLK:
AddDev();
return 0;
case LBN_SELCHANGE:
Update();
return 0;
}
return 0;
}
return CDlg::Command(wNotifyCode,wID,hwndCtl);
}
INT_PTR CAddDlg::DialogProc(UINT uMsg,WPARAM wParam,LPARAM lParam)
{
switch(uMsg)
{
case WM_VKEYTOITEM:
if(LOWORD(wParam)==VK_DELETE)
{
HWND hListCtrl=HDlgItem(IDC_DEVICE_LIST);
if(hListCtrl)
{
int nSelDev=LBGetCurSel(hListCtrl);
LPCTSTR pTypeName=LBGetItemTypeName(hListCtrl,nSelDev);
if(pTypeName)
{
if(m_pCore->IsCustomDevice(pTypeName))
{
if(!m_pCore->IsDeviceActive(pTypeName))
{
CGprtDev *pDev=m_pCore->FindGprtDev(pTypeName);
if(!pDev) {
//This should never happend, but just in case.
throw JOY_EXCEPTION(E_FAIL);
}
TCHAR S[128];
LoadString(m_hModule,IDS_GEN_AREYOUSURE, S, cA(S));
LPTSTR pT = Insert1String(S,pDev->Name());
lstrcpy(S, pT);
delete[] pT;
TCHAR Title[128];
LoadString(m_hModule,IDS_GEN_AREYOUSURE_TITLE, Title, cA(Title));
UINT uRTL = (GetWindowLongPtr(m_hWnd,GWL_EXSTYLE) & WS_EX_LAYOUTRTL) ? MB_RTLREADING : 0;
if(MessageBox(m_hWnd,S,Title,
MB_ICONQUESTION|MB_YESNO|MB_APPLMODAL|uRTL)==IDYES)
{
m_pCore->DeleteType(pTypeName);
}
}
else
{
MessageBox(m_hWnd,m_hModule,IDS_GEN_AREYOUSURE_TITLE,IDS_NO_REMOVE);
}
}
}
}
}
else return -1;
return 0;
}
return CDlg::DialogProc(uMsg,wParam,lParam);
}
/******************************************************************************
Custom dialog
******************************************************************************/
#define MAX_ANALOG_BUTTONS 4
#define MIN_ANALOG_AXIS 2
#define MAX_ANALOG_AXIS 4
#define MAX_STR_LEN 255
BOOL CCustomDlg::InitDialog(HWND hFocus,LPARAM lParam)
{
if(!m_pCore->IsAvailableVIDPID(m_VIDPIDName))
{
MessageBox(m_hWnd,m_hModule,IDS_NO_NAME_TITLE,IDS_NOAVAILABLEVIDPID);
EndDialog(m_hWnd,IDCANCEL);
return TRUE;
}
HWND hButtons=HDlgItem(IDC_COMBO_BUTTONS);
if(hButtons)
{
for(int i=0;i<=MAX_ANALOG_BUTTONS;i++)
{
TCHAR Str[32];
_sntprintf(Str,32,_T("%d"),i);
Str[31]=0;
ComboBox_InsertString(hButtons,i,Str);
}
ComboBox_SetCurSel(hButtons,MAX_ANALOG_BUTTONS);
}
HWND hAxis=HDlgItem(IDC_COMBO_AXIS);
if(hAxis)
{
for(int i=MIN_ANALOG_AXIS;i<=MAX_ANALOG_AXIS;i++)
{
TCHAR Str[32];
_sntprintf(Str,32,_T("%d"),i);
Str[31]=0;
ComboBox_InsertString(hAxis,i-MIN_ANALOG_AXIS,Str);
}
ComboBox_SetCurSel(hAxis,0);
}
HWND hSpecJoy=HDlgItem(IDC_SPECIAL_JOYSTICK);
if(hSpecJoy)
Button_SetCheck(hSpecJoy,BST_CHECKED);
HWND hEdit=HDlgItem(IDC_EDIT_NAME);
if(hEdit)
Edit_LimitText(hEdit,MAX_STR_LEN);
HWND hHasZAxis=HDlgItem(IDC_HASZAXIS);
if(hHasZAxis)
Button_SetCheck(hHasZAxis,BST_CHECKED);
return TRUE;
}
INT_PTR CCustomDlg::Command(WORD wNotifyCode,WORD wID,HWND hwndCtl)
{
switch(wID)
{
case IDOK:
{
HWND hJoy=HDlgItem(IDC_SPECIAL_JOYSTICK);
HWND hYoke=HDlgItem(IDC_SPECIAL_YOKE);
HWND hPad=HDlgItem(IDC_SPECIAL_PAD);
HWND hCar=HDlgItem(IDC_SPECIAL_AUTO);
HWND hAxis=HDlgItem(IDC_COMBO_AXIS);
HWND hRudder=HDlgItem(IDC_HASRUDDER);
HWND hZAxis=HDlgItem(IDC_HASZAXIS);
HWND hButtons=HDlgItem(IDC_COMBO_BUTTONS);
HWND hPov=HDlgItem(IDS_CUSTOM_HASPOV);
HWND hEdit=HDlgItem(IDC_EDIT_NAME);
if(hJoy&&
hYoke&&
hPad&&
hCar&&
hAxis&&
hRudder&&
hZAxis&&
hButtons&&
hPov&&
hEdit)//Possible internal error.
{
TCHAR *pStr=NULL;
bool bErr=false;
int nLen=Edit_LineLength(hEdit,0);//Possible internal error.
if(!nLen)
{
bErr=true;
MessageBox(m_hWnd,m_hModule,IDS_NO_NAME_TITLE,IDS_NO_NAME);
}
else
{
pStr=new TCHAR[nLen+1];
if (pStr == NULL)
return 0; //Internal error
if(GetDlgItemText(m_hWnd,IDC_EDIT_NAME,pStr,nLen+1)!=nLen)
return 0;//Internal error.
if(_tcschr(pStr,_T('\\')))
{
bErr=true;
MessageBox(m_hWnd,m_hModule,IDS_NO_NAME_TITLE,IDS_INVALID_NAME);
}
else
{
if(m_pCore->DuplicateDeviceName(pStr))
{
bErr=true;
MessageBox(m_hWnd,m_hModule,IDS_NO_NAME_TITLE,IDS_DUPLICATE_TYPE);
}
}
}
if(bErr)//User entered invalid text for name.
{
SetFocus(m_hWnd);
SetFocus(hEdit);
Edit_SetSel(hEdit,0,-1);
return 0;
}
m_pCore->AddCustomDevice(
(Button_GetCheck(hJoy)==BST_CHECKED)?true:false,
(Button_GetCheck(hPad)==BST_CHECKED)?true:false,
(Button_GetCheck(hYoke)==BST_CHECKED)?true:false,
(Button_GetCheck(hCar)==BST_CHECKED)?true:false,
ComboBox_GetCurSel(hAxis)+MIN_ANALOG_AXIS,
(Button_GetCheck(hZAxis)==BST_CHECKED)?true:false,
ComboBox_GetCurSel(hButtons),
(Button_GetCheck(hPov)==BST_CHECKED)?true:false,
pStr,
m_VIDPIDName.data());
if( pStr ) {
delete[] pStr;
}
}
}
EndDialog(m_hWnd,IDOK);
return 0;
case IDC_COMBO_AXIS:
if(wNotifyCode==CBN_SELCHANGE)
{
HWND hAxis=HDlgItem(IDC_COMBO_AXIS);
if(hAxis)
{
UINT uShow=SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER;
if((ComboBox_GetCurSel(hAxis)+MIN_ANALOG_AXIS)==3)//If 3 axis selected.
uShow|=SWP_SHOWWINDOW;
else
uShow|=SWP_HIDEWINDOW;
HWND hHasZAxis=HDlgItem(IDC_HASZAXIS);
if(hHasZAxis)
{
SetWindowPos(hHasZAxis,NULL,NULL,NULL,NULL,NULL,uShow);
}
HWND hHasRudder=HDlgItem(IDC_HASRUDDER);
if(hHasRudder)
{
SetWindowPos(hHasRudder,NULL,NULL,NULL,NULL,NULL,uShow);
}
}
}
return 0;
}
return CDlg::Command(wNotifyCode,wID,hwndCtl);
}
/******************************************************************************
Preferred dialog
******************************************************************************/
void CPreferredDlg::Preferred()
{
HWND hListCtrl=HDlgItem(IDC_CHANGE_LIST);
if(hListCtrl)
{
int nSelDev=CBGetCurSel(hListCtrl);
GUID SelGUID=CBGetItemGUID(hListCtrl,nSelDev);
if(SelGUID!=NULLGUID)
m_pCore->Preferred(SelGUID);
}
EndDialog(m_hWnd,IDOK);
}
INT_PTR CPreferredDlg::Command(WORD wNotifyCode,WORD wID,HWND hwndCtl)
{
switch(wID)
{
case IDOK:
Preferred();
return 0;
}
if(wNotifyCode==CBN_CLOSEUP)
{
Update();
return 0;
}
return CDlg::Command(wNotifyCode,wID,hwndCtl);
}
BOOL CPreferredDlg::InitDialog(HWND hFocus,LPARAM lParam)
{
Update();
HWND hListCtrl=HDlgItem(IDC_CHANGE_LIST);
if(hListCtrl)
{
for(LISTDIDEV::iterator It=m_pCore->m_ListDIDev.begin();
It!=m_pCore->m_ListDIDev.end();It++)
{
if(It->Id()==0)
{
int nSelDev=CBFindGUIDIndex(hListCtrl,It->InstGUID());
if(nSelDev>=0)
ComboBox_SetCurSel(hListCtrl,nSelDev);
break;
}
}
}
return TRUE;
}
void CPreferredDlg::Update()
{
if(m_bBlockUpdate)return;//Some actions may send notify messages which then Update and overflow stack.
CUpdate U(&m_bBlockUpdate);
if(!m_hWnd)return;
int nSelDev=-1;
GUID SelGUID=NULLGUID;
HWND hListCtrl=HDlgItem(IDC_CHANGE_LIST);
if(hListCtrl)
{
if(ComboBox_GetDroppedState(hListCtrl))return;//No update when selecting preferred.
int nCount=CBGetCnt(hListCtrl);
nSelDev=CBGetCurSel(hListCtrl);
SelGUID=CBGetItemGUID(hListCtrl,nSelDev);
SetWindowRedraw(hListCtrl,FALSE);
ComboBox_ResetContent(hListCtrl);
m_ListCtrl.clear();//Must be behind ComboBox_ResetContent.
int nId0Index=-1;//Index of preferred device.
for(LISTDIDEV::iterator It=m_pCore->m_ListDIDev.begin();
It!=m_pCore->m_ListDIDev.end();It++)
{
GUID G=It->InstGUID();
m_ListCtrl.push_back(G);
int nIndex=ComboBox_AddString(hListCtrl,It->InstName());
ComboBox_SetItemData(hListCtrl,nIndex,&m_ListCtrl.back());
if(It->Id()==0)
nId0Index=nIndex;
}
int nNoneIndex=-1;
if(nId0Index<0)//Only if there is no preferred device.
{
TCHAR None[256];
LoadString(m_hModule,IDS_NONE, None, cA(None));
nNoneIndex=ComboBox_AddString(hListCtrl,None);
}
if((!nCount)||//First update during init.
(SelGUID==NULLGUID))//Or none is selected.
{
if(nId0Index>=0)//Preferred device was added.
ComboBox_SetCurSel(hListCtrl,nId0Index);
else//There is no preferred device.
ComboBox_SetCurSel(hListCtrl,nNoneIndex);
}
else//List was not empty before update. Select same thing.
{
nSelDev=CBFindGUIDIndex(hListCtrl,SelGUID);
if(nSelDev>=0)
ComboBox_SetCurSel(hListCtrl,nSelDev);
else//Selected device removed.
{
if(nId0Index>=0)//Then select original preferred device.
ComboBox_SetCurSel(hListCtrl,nId0Index);
else//Select none.
ComboBox_SetCurSel(hListCtrl,nNoneIndex);
}
}
SetWindowRedraw(hListCtrl,TRUE);
InvalidateRect(hListCtrl,NULL,TRUE);
}
}
INT_PTR CPreferredDlg::Notify(int idCtrl,LPNMHDR pnmh)
{
// switch(pnmh->code)
// {
/*case LVN_KEYDOWN:
switch(((LV_KEYDOWN*)pnmh)->wVKey)
{
case VK_F5:
CoreUpdate();
return 0;
}
return 0;
case LVN_ITEMCHANGED:
Update();
return 0;*/
/* case NM_DBLCLK:
switch(pnmh->idFrom)
{
case IDC_CHANGE_LIST:
Preferred();
return 0;
}
return 0;*/
// }
return 0;
}
/******************************************************************************
Connect UI and core
******************************************************************************/
class CCP:public CCore,public CMainDlg
{
virtual void UIUpdate(){CMainDlg::Update();};
public:
CCP(){ConnectUI((CCore*)this);};
};
/******************************************************************************
Entry point.
******************************************************************************/
#define MUTEX_NAME _T("$$$MS_GameControllers_Cpl$$$")
void Core(HANDLE hModule,HWND hWnd)
{
static HWND hPrevHwnd=NULL;
static HANDLE hMutex=CreateMutex(NULL,TRUE,MUTEX_NAME);
if(GetLastError()==ERROR_ALREADY_EXISTS)
{
SetForegroundWindow(hPrevHwnd);
}
else
{
hPrevHwnd=hWnd;
_PNH _old_handler;
_old_handler = _set_new_handler(my_new_handler);
if( SHFusionInitializeFromModuleID((HMODULE)hModule,124) )
{
// While not initializing would only cause theming to be inactive,
// a failure to initialize indicates a much worse problem so since
// PREFIX warns (656863) that the return needs to be tested, abort
// if the initialization fails.
try
{
CCP CP;
CP.Dlg(IDD_CPANEL,(HMODULE)hModule,hWnd);
}
catch(JoyException E)
{
}
catch(exception)
{
}
SHFusionUninitialize();
}
_set_new_handler(_old_handler);
ReleaseMutex(hMutex);
CloseHandle(hMutex);
}
}
/******************************************************************************
Propertiy
******************************************************************************/
class CoInit
{
HRESULT m_hRes;
public:
~CoInit()
{
if(SUCCEEDED(m_hRes))
{
CoFreeUnusedLibraries();//Free gcdef.dll.
CoUninitialize();
}
};
CoInit(){m_hRes=CoInitialize(NULL);};
operator HRESULT(){return m_hRes;};
};
typedef HPROPSHEETPAGE *LPHPROPSHEETPAGE;
typedef AutoDeleteArray<LPHPROPSHEETPAGE> LPHPROPSHEETPAGE_ADAR;
//FUN! FUN! FUN! FUN!
//This is certain funny code written by some other, quite funny people,
//so I will put it in the funny code section at the end of the otherwise
//serious file.
//tmarkoc cleaned it up. No more memory/interface/freelib leaks, alloc failures handled, no unneccessary allocations.
/*
#ifndef PPVOID
typedef LPVOID* PPVOID;
#endif
//WHAT IS THIS FOR????????????????????????????????????????????????????????
class CDIGameCntrlPropSheet : public IDIGameCntrlPropSheet
{
private:
DWORD m_cProperty_refcount;
public:
CDIGameCntrlPropSheet(void);
~CDIGameCntrlPropSheet(void);
// IUnknown methods
STDMETHODIMP QueryInterface(REFIID, PPVOID);
STDMETHODIMP_(ULONG) AddRef(void);
STDMETHODIMP_(ULONG) Release(void);
// CImpIServerProperty methods
STDMETHODIMP GetSheetInfo(LPDIGCSHEETINFO *lpSheetInfo);
STDMETHODIMP GetPageInfo (LPDIGCPAGEINFO *lpPageInfo );
STDMETHODIMP SetID(USHORT nID);
STDMETHODIMP_(USHORT) GetID(void);
};*/
//typedef CDIGameCntrlPropSheet *LPCDIGAMECNTRLPROPSHEET;
typedef IDIGameCntrlPropSheet *LPCDIGAMECNTRLPROPSHEET;
typedef AutoRelease<LPCDIGAMECNTRLPROPSHEET> LPCDIGAMECNTRLPROPSHEET_AR;
HRESULT Properties(HMODULE hMod,HWND hWnd,CCore *pCore,DWORD dwId)
{
// ASSERT(IsWindow(hWnd));
CLSID clsidPropSheet=CLSID_LegacyServer;
//Get type name.
DIJOYCONFIG DIJoyCfg;
ZeroMemory(&DIJoyCfg,sizeof(DIJoyCfg));
DIJoyCfg.dwSize=sizeof(DIJoyCfg);
if(SUCCEEDED(pCore->m_pDIJoyCfg->GetConfig(dwId,&DIJoyCfg,DIJC_REGHWCONFIGTYPE|DIJC_CALLOUT)))
{
//Get the clsidConfig.
DIJOYTYPEINFO DIJoyType;
ZeroMemory(&DIJoyType,sizeof(DIJoyType));
DIJoyType.dwSize=sizeof(DIJoyType);
if(SUCCEEDED(pCore->m_pDIJoyCfg->GetTypeInfo(DIJoyCfg.wszType,&DIJoyType,DITC_CLSIDCONFIG|DITC_REGHWSETTINGS|DITC_FLAGS1)))
{
if((DIJoyType.clsidConfig!=GUID_NULL)&&
!(DIJoyType.dwFlags1&JOYTYPE_DEFAULTPROPSHEET))
clsidPropSheet=DIJoyType.clsidConfig;
}
}
int nStartPage=(clsidPropSheet==CLSID_LegacyServer)?1:0;
if(nStartPage>MAX_PAGES)
return(DIGCERR_STARTPAGETOOLARGE);
CoInit CI;//CoInitialize(NULL); Auto CoFreeUnusedLibraries();CoUninitialize();.
LPCDIGAMECNTRLPROPSHEET_AR fnInterface;
if(SUCCEEDED(CI))
{
IClassFactory* pCF;
if(SUCCEEDED(CoGetClassObject(clsidPropSheet,CLSCTX_INPROC_SERVER,NULL,IID_IClassFactory,(LPVOID*)&pCF)))
{
pCF->CreateInstance(NULL,IID_IDIGameCntrlPropSheet,(LPVOID*)&fnInterface);
pCF->Release();
}
else
{
//reset to legacy server
clsidPropSheet=CLSID_LegacyServer;
nStartPage=1;
if(SUCCEEDED(CoGetClassObject(clsidPropSheet,CLSCTX_INPROC_SERVER,NULL,IID_IClassFactory,(LPVOID*)&pCF)))
{
pCF->CreateInstance(NULL,IID_IDIGameCntrlPropSheet,(LPVOID*)&fnInterface);
pCF->Release();
}
}
}
if(*((PVOID *)&fnInterface) == NULL)
{
return(E_NOINTERFACE);
}
//Send device Id to the property sheet.
fnInterface->SetID(dwId);
LPDIGCSHEETINFO pServerSheet=NULL;
//Get the property sheet info from the server.
if(FAILED(fnInterface->GetSheetInfo(&pServerSheet)))
{
return(E_FAIL);
}
//Verify data from server.
if(pServerSheet->nNumPages==0)
return(DIGCERR_NUMPAGESZERO);
else if((pServerSheet->nNumPages>MAX_PAGES)||(pServerSheet->nNumPages<nStartPage))
return(DIGCERR_NUMPAGESTOOLARGE);
LPDIGCPAGEINFO pServerPage=NULL;
//Get the information for all the pages from the server.
if(FAILED(fnInterface->GetPageInfo(&pServerPage)))
{
return(E_FAIL);
}
// Allocate memory for the pages.
LPHPROPSHEETPAGE_ADAR pPages=new HPROPSHEETPAGE[pServerSheet->nNumPages];
if(*((PVOID *)&pPages) == NULL) return(E_OUTOFMEMORY);
ZeroMemory((LPHPROPSHEETPAGE)pPages,sizeof(HPROPSHEETPAGE)*pServerSheet->nNumPages);
// Allocate memory for the header!
PROPSHEETHEADER SH;
ZeroMemory(&SH,sizeof(SH));
SH.dwSize=sizeof(SH);
SH.hwndParent= hWnd;
SH.hInstance=pServerPage[0].hInstance;
if(pServerSheet->fSheetIconFlag)
{
if(pServerSheet->lpwszSheetIcon)
{
//Check to see if you are an INT or a WSTR.
if(HIWORD((INT_PTR)pServerSheet->lpwszSheetIcon))
{
//You are a string.
SH.pszIcon=pServerSheet->lpwszSheetIcon;
}
else
SH.pszIcon=(LPCTSTR)(pServerSheet->lpwszSheetIcon);
SH.dwFlags=PSH_USEICONID;
}
else return(DIGCERR_NOICON);
}
//Do we have a sheet caption?
if(pServerSheet->lpwszSheetCaption)
{
SH.pszCaption=pServerSheet->lpwszSheetCaption;
SH.dwFlags|=PSH_PROPTITLE;
}
SH.nPages=pServerSheet->nNumPages;
SH.nStartPage=nStartPage;
//Set the property pages inofrmation into the header.
SH.phpage=(LPHPROPSHEETPAGE)pPages;
//Sheet stuff is done.Now do the pages.
PROPSHEETPAGE PropPage;
ZeroMemory(&PropPage,sizeof(PropPage));
PropPage.dwSize=sizeof(PropPage);
//Fill up each page.
int nIndex=0;
do
{
//Assign the things that there are not questionable.
PropPage.lParam=pServerPage[nIndex].lParam;
PropPage.hInstance=pServerPage[nIndex].hInstance;
// Add the title.
if(pServerPage[nIndex].lpwszPageTitle)
{
PropPage.dwFlags=PSP_USETITLE;
//Check to see if you are a string.
if(HIWORD((INT_PTR)pServerPage[nIndex].lpwszPageTitle))
{
PropPage.pszTitle=pServerPage[nIndex].lpwszPageTitle;
}
else
PropPage.pszTitle=(LPTSTR)pServerPage[nIndex].lpwszPageTitle;
}
else PropPage.pszTitle=NULL;
//If icon is required go ahead and add it.
if(pServerPage[nIndex].fIconFlag)
{
PropPage.dwFlags|=PSP_USEICONID;
//Check to see if you are an INT or a String.
if(HIWORD((INT_PTR)pServerPage[nIndex].lpwszPageIcon))
{
//You're a string.
PropPage.pszIcon=pServerPage[nIndex].lpwszPageIcon;
}
else
PropPage.pszIcon=(LPCTSTR)(pServerPage[nIndex].lpwszPageIcon);
}
//If a pre - post processing call back proc is required go ahead and add it.
if(pServerPage[nIndex].fProcFlag)
{
if(pServerPage[nIndex].fpPrePostProc)
{
PropPage.dwFlags|=PSP_USECALLBACK;
PropPage.pfnCallback=(LPFNPSPCALLBACK)pServerPage[nIndex].fpPrePostProc;
}
else
return(DIGCERR_NOPREPOSTPROC);
}
//And the essential "dialog" proc.
if(pServerPage[nIndex].fpPageProc)
PropPage.pfnDlgProc=pServerPage[nIndex].fpPageProc;
else
return(DIGCERR_NODLGPROC);
//Assign the dialog template.
if(HIWORD((INT_PTR)pServerPage[nIndex].lpwszTemplate))
{
PropPage.pszTemplate=pServerPage[nIndex].lpwszTemplate;
}
else
PropPage.pszTemplate=(LPTSTR)pServerPage[nIndex].lpwszTemplate;
if(clsidPropSheet!=CLSID_LegacyServer)//If third party software do not enforce theme.
((LPHPROPSHEETPAGE)pPages)[nIndex++]=SHNoFusionCreatePropertySheetPageW(&PropPage);
else
((LPHPROPSHEETPAGE)pPages)[nIndex++]=CreatePropertySheetPage(&PropPage);
}
while(nIndex<pServerSheet->nNumPages);
//Launch modal property sheet dialog.
PropertySheet(&SH);
pCore->Update();
return(S_OK);
}
#undef cA