|
|
/****************************************************************************
* * 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
|