881 lines
25 KiB
C
881 lines
25 KiB
C
/*****************************************************************************
|
|
*
|
|
* diquick.c
|
|
*
|
|
* DirectInput quick test
|
|
*
|
|
*****************************************************************************/
|
|
|
|
#include "diquick.h"
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* GetCheckedRadioButton
|
|
*
|
|
* Return the ID of the one that is checked.
|
|
*
|
|
* If nothing is checked, we return idFirst.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
UINT EXTERNAL
|
|
GetCheckedRadioButton(HWND hdlg, UINT idFirst, UINT idLast)
|
|
{
|
|
for (; idFirst < idLast; idLast--) {
|
|
if (IsDlgButtonChecked(hdlg, idLast)) {
|
|
return idLast;
|
|
}
|
|
}
|
|
return idLast;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* MessageBoxV
|
|
*
|
|
* Format a message and display a message box.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
int __cdecl
|
|
MessageBoxV(HWND hdlg, UINT ids, ...)
|
|
{
|
|
va_list ap;
|
|
TCHAR tszStr[256] = {0};
|
|
TCHAR tszBuf[1024] = {0};
|
|
|
|
LoadString(g_hinst, ids, tszStr, cA(tszStr));
|
|
va_start(ap, ids);
|
|
#ifdef WIN95
|
|
{
|
|
char *psz = NULL;
|
|
char szDfs[1024]={0};
|
|
strcpy(szDfs,tszStr); // make a local copy of format string
|
|
while (psz = strstr(szDfs,"%p")) // find each %p
|
|
*(psz+1) = 'x'; // replace each %p with %x
|
|
wvsprintf(tszBuf, szDfs, ap); // use the local format string
|
|
}
|
|
#else
|
|
{
|
|
wvsprintf(tszBuf, tszStr, ap);
|
|
}
|
|
#endif
|
|
va_end(ap);
|
|
return MessageBox(hdlg, tszBuf, TEXT("DirectInput QuickTest"), MB_OK);
|
|
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* ThreadFailHres
|
|
*
|
|
* Tell the parent that a thread failed to start, and display
|
|
* an error message with an HRESULT code.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
int EXTERNAL
|
|
ThreadFailHres(HWND hdlg, UINT ids, HRESULT hres)
|
|
{
|
|
SendNotifyMessage(hdlg, WM_THREADSTARTED, 0, 0);
|
|
SendNotifyMessage(hdlg, WM_CHILDEXIT, 0, 0);
|
|
|
|
return MessageBoxV(hdlg, ids, hres);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* RecalcCursor
|
|
*
|
|
* If the cursor is over the window, force a new WM_SETCUSOR.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
void EXTERNAL
|
|
RecalcCursor(HWND hdlg)
|
|
{
|
|
POINT pt;
|
|
HWND hwnd;
|
|
GetCursorPos(&pt);
|
|
hwnd = WindowFromPoint(pt);
|
|
if( (hwnd != NULL) && (hwnd == hdlg || IsChild(hdlg, hwnd)) ) {
|
|
SetCursorPos(pt.x, pt.y);
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* ModalVtbl
|
|
*
|
|
* Things that tell you about the modal gizmo.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
typedef struct MODALVTBL {
|
|
BOOL (WINAPI *IsDialogMessage)(HWND, LPMSG);
|
|
BOOL (WINAPI *IsAlive)(HWND);
|
|
void (INTERNAL *SendIdle)(HWND);
|
|
} MODALVTBL, *PMODALVTBL;
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* ModalLoop
|
|
*
|
|
* Spin waiting for the dialog box to die.
|
|
*
|
|
* WEIRDNESS! We send the WM_SELFENTERIDLE message to the dialog box
|
|
* rather than to the owner. This avoids inter-thread sendmessage goo.
|
|
*
|
|
* Don't re-post the quit message if we get one. The purpose of the
|
|
* quit message is to break the modal loop.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
int EXTERNAL
|
|
ModalLoop(HWND hwndOwner, HWND hdlg, PMODALVTBL pvtbl)
|
|
{
|
|
if (hdlg) {
|
|
BOOL fSentIdle = 0;
|
|
while (pvtbl->IsAlive(hdlg)) {
|
|
MSG msg;
|
|
if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
|
|
fSentIdle = 0;
|
|
if (msg.message == WM_QUIT) {
|
|
break;
|
|
}
|
|
if (!pvtbl->IsDialogMessage(hdlg, &msg)) {
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
} else {
|
|
if (fSentIdle) {
|
|
WaitMessage();
|
|
} else {
|
|
fSentIdle = 1;
|
|
pvtbl->SendIdle(hdlg);
|
|
}
|
|
}
|
|
}
|
|
if (IsWindow(hdlg)) {
|
|
DestroyWindow(hdlg);
|
|
}
|
|
}
|
|
|
|
SendNotifyMessage(hwndOwner, WM_CHILDEXIT, 0, 0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* SendDlgIdle
|
|
*
|
|
* Send the fake idle message.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
void INTERNAL
|
|
SendDlgIdle(HWND hdlg)
|
|
{
|
|
SendMessage(hdlg, WM_SELFENTERIDLE, MSGF_DIALOGBOX, (LPARAM)hdlg);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* SemimodalDialogBoxParam
|
|
*
|
|
* Create a non-modal dialog box, then spin waiting for it to die.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
#pragma BEGIN_CONST_DATA
|
|
|
|
MODALVTBL c_dlgvtbl = {
|
|
IsDialogMessage,
|
|
IsWindow,
|
|
SendDlgIdle,
|
|
};
|
|
|
|
#pragma END_CONST_DATA
|
|
|
|
int EXTERNAL
|
|
SemimodalDialogBoxParam(UINT idd, HWND hwndOwner, DLGPROC dp, LPARAM lp)
|
|
{
|
|
return ModalLoop(hwndOwner, CreateDialogParam(g_hinst,
|
|
(LPVOID)(UINT_PTR)idd, hwndOwner, dp, lp), &c_dlgvtbl);
|
|
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* IsPrshtMessage
|
|
*
|
|
*****************************************************************************/
|
|
|
|
BOOL WINAPI
|
|
IsPrshtMessage(HWND hdlg, LPMSG pmsg)
|
|
{
|
|
return PropSheet_IsDialogMessage(hdlg, pmsg);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* IsPrshtAlive
|
|
*
|
|
*****************************************************************************/
|
|
|
|
BOOL WINAPI
|
|
IsPrshtAlive(HWND hdlg)
|
|
{
|
|
return (BOOL)(INT_PTR)PropSheet_GetCurrentPageHwnd(hdlg);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* SendPrshtIdle
|
|
*
|
|
* Send the fake idle message.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
void INTERNAL
|
|
SendPrshtIdle(HWND hdlg)
|
|
{
|
|
hdlg = PropSheet_GetCurrentPageHwnd(hdlg);
|
|
SendDlgIdle(hdlg);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* SemimodalPropertySheet
|
|
*
|
|
* Create a non-modal property sheet, then spin waiting for it to die.
|
|
*
|
|
* We nuke the Cancel and Apply buttons, change OK to Close, and move
|
|
* the button into the corner.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
#pragma BEGIN_CONST_DATA
|
|
|
|
MODALVTBL c_pshvtbl = {
|
|
IsPrshtMessage,
|
|
IsPrshtAlive,
|
|
SendPrshtIdle,
|
|
};
|
|
|
|
#pragma END_CONST_DATA
|
|
|
|
int EXTERNAL
|
|
SemimodalPropertySheet(HWND hwndOwner, LPPROPSHEETHEADER ppsh)
|
|
{
|
|
HWND hdlg = (HWND)PropertySheet(ppsh);
|
|
if ( hdlg && hdlg != (HWND)-1 ) {
|
|
RECT rcOk, rcCancel;
|
|
HWND hwnd;
|
|
PropSheet_CancelToClose(hdlg);
|
|
|
|
/* Slide the Close button to where the Cancel button is */
|
|
hwnd = GetDlgItem(hdlg, IDCANCEL);
|
|
GetWindowRect(hwnd, &rcCancel);
|
|
ShowWindow(hwnd, SW_HIDE);
|
|
|
|
hwnd = GetDlgItem(hdlg, IDOK);
|
|
GetWindowRect(hwnd, &rcOk);
|
|
|
|
rcOk.left += rcCancel.right - rcOk.right;
|
|
ScreenToClient(hdlg, (LPPOINT)&rcOk);
|
|
SetWindowPos(hwnd, 0, rcOk.left, rcOk.top, 0, 0,
|
|
SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
|
|
|
|
return ModalLoop(hwndOwner, hdlg, &c_pshvtbl);
|
|
} else {
|
|
return -1;
|
|
}
|
|
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* CreateDI
|
|
*
|
|
* Create an IDirectInput interface in the appropriate manner.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
#pragma BEGIN_CONST_DATA
|
|
|
|
/*
|
|
* This table must be in sync with the CDIFL_* values.
|
|
*/
|
|
const IID *c_rgiidDI[] = {
|
|
&IID_IDirectInputA, /* */
|
|
&IID_IDirectInputW, /* CDIFL_UNICODE */
|
|
&IID_IDirectInput2A, /* CDIFL_DI2 */
|
|
&IID_IDirectInput2W, /* CDIFL_UNICODE | CDIFL_DI2 */
|
|
};
|
|
|
|
#pragma END_CONST_DATA
|
|
|
|
|
|
STDMETHODIMP
|
|
CreateDI(BOOL fOle, UINT flCreate, PV ppvOut)
|
|
{
|
|
HRESULT hres;
|
|
if (fOle) {
|
|
const IID *piid = c_rgiidDI[flCreate];
|
|
hres = CoCreateInstance(&CLSID_DirectInput, 0, CLSCTX_INPROC_SERVER,
|
|
piid, ppvOut);
|
|
if (SUCCEEDED(hres)) {
|
|
LPDIRECTINPUT pdi = *(PPV)ppvOut;
|
|
hres = pdi->lpVtbl->Initialize(pdi, g_hinst, g_dwDIVer);
|
|
if (FAILED(hres)) {
|
|
pdi->lpVtbl->Release(pdi);
|
|
*(PPV)ppvOut = 0;
|
|
}
|
|
}
|
|
} else { /* Create via DI */
|
|
if (flCreate & CDIFL_UNICODE) {
|
|
hres = DirectInputCreateW(g_hinst, g_dwDIVer, ppvOut, 0);
|
|
} else {
|
|
hres = DirectInputCreateA(g_hinst, g_dwDIVer, ppvOut, 0);
|
|
}
|
|
|
|
/*
|
|
* If necessary, QI for the 2 interface.
|
|
*/
|
|
if (flCreate & CDIFL_DI2) {
|
|
LPDIRECTINPUT pdi = *(PPV)ppvOut;
|
|
hres = pdi->lpVtbl->QueryInterface(pdi, c_rgiidDI[flCreate],
|
|
ppvOut);
|
|
pdi->lpVtbl->Release(pdi);
|
|
}
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* GetDwordProperty
|
|
*
|
|
* Get a DWORD property from an IDirectInputDevice.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
STDMETHODIMP
|
|
GetDwordProperty(IDirectInputDevice *pdid, PCGUID pguid, LPDWORD pdw)
|
|
{
|
|
HRESULT hres;
|
|
DIPROPDWORD dipdw;
|
|
|
|
dipdw.diph.dwSize = sizeof(DIPROPDWORD);
|
|
dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
|
|
dipdw.diph.dwObj = 0;
|
|
dipdw.diph.dwHow = DIPH_DEVICE;
|
|
|
|
hres = IDirectInputDevice_GetProperty(pdid, pguid, &dipdw.diph);
|
|
if (SUCCEEDED(hres)) {
|
|
*pdw = dipdw.dwData;
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* SetDwordProperty
|
|
*
|
|
* Set a DWORD property into an IDirectInputDevice.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
STDMETHODIMP
|
|
SetDwordProperty(IDirectInputDevice *pdid, PCGUID pguid, DWORD dw)
|
|
{
|
|
DIPROPDWORD dipdw;
|
|
|
|
dipdw.diph.dwSize = sizeof(DIPROPDWORD);
|
|
dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
|
|
dipdw.diph.dwObj = 0;
|
|
dipdw.diph.dwHow = DIPH_DEVICE;
|
|
dipdw.dwData = dw;
|
|
|
|
return IDirectInputDevice_SetProperty(pdid, pguid, &dipdw.diph);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* ConvertString
|
|
*
|
|
* Convert a string from whatever character set it is in into
|
|
* the preferred character set (ANSI or UNICODE, whichever we
|
|
* were compiled with).
|
|
*
|
|
* This is used to convert strings received from DirectInput
|
|
* into something we like.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
void EXTERNAL
|
|
ConvertString(BOOL fWide, LPCVOID pvIn, LPTSTR ptszOut, UINT ctchOut)
|
|
{
|
|
if (fTchar(fWide)) {
|
|
lstrcpyn(ptszOut, pvIn, ctchOut);
|
|
} else {
|
|
#ifdef UNICODE
|
|
MultiByteToWideChar(CP_ACP, 0, pvIn, -1, ptszOut, ctchOut);
|
|
#else
|
|
WideCharToMultiByte(CP_ACP, 0, pvIn, -1, ptszOut, ctchOut, 0, 0);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* UnconvertString
|
|
*
|
|
* Convert a string from the preferred character set
|
|
* (ANSI or UNICODE, whichever we were compiled with)
|
|
* into the specified character set.
|
|
*
|
|
* This is used to convert strings generated from dialogs
|
|
* into something that DirectInput will like.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
void EXTERNAL
|
|
UnconvertString(BOOL fWide, LPCTSTR ptszIn, LPVOID pvOut, UINT ctchOut)
|
|
{
|
|
if (fTchar(fWide)) {
|
|
lstrcpyn(pvOut, ptszIn, ctchOut);
|
|
} else {
|
|
#ifdef UNICODE
|
|
WideCharToMultiByte(CP_ACP, 0, ptszIn, -1, pvOut, ctchOut, 0, 0);
|
|
#else
|
|
MultiByteToWideChar(CP_ACP, 0, ptszIn, -1, pvOut, ctchOut);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* ConvertDoi
|
|
*
|
|
* Convert the pvDoi into the local character set.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
void EXTERNAL
|
|
ConvertDoi(PDEVDLGINFO pddi, LPDIDEVICEOBJECTINSTANCE pdoi, LPCVOID pvDoi)
|
|
{
|
|
if (IsUnicodeDidc(pddi->didcItf)) {
|
|
LPCDIDEVICEOBJECTINSTANCEW pdoiW = pvDoi;
|
|
ConvertString(TRUE,
|
|
pdoiW->tszName, pdoi->tszName, cA(pdoi->tszName));
|
|
pdoi->guidType = pdoiW->guidType;
|
|
pdoi->dwOfs = pdoiW->dwOfs;
|
|
pdoi->dwType = pdoiW->dwType;
|
|
pdoi->dwFlags = pdoiW->dwFlags;
|
|
pdoi->dwSize = sizeof(DIDEVICEOBJECTINSTANCE_DX3);
|
|
pdoi->wReportId = pdoiW->wReportId;
|
|
|
|
if (pdoiW->dwSize > cbX(DIDEVICEOBJECTINSTANCE_DX3W)) {
|
|
pdoi->dwFFMaxForce = pdoiW->dwFFMaxForce;
|
|
pdoi->dwFFForceResolution = pdoiW->dwFFForceResolution;
|
|
pdoi->wCollectionNumber = pdoiW->wCollectionNumber;
|
|
pdoi->wDesignatorIndex = pdoiW->wDesignatorIndex;
|
|
pdoi->wUsagePage = pdoiW->wUsagePage;
|
|
pdoi->wUsage = pdoiW->wUsage;
|
|
pdoi->dwSize = sizeof(DIDEVICEOBJECTINSTANCE);
|
|
}
|
|
|
|
} else {
|
|
LPCDIDEVICEOBJECTINSTANCEA pdoiA = pvDoi;
|
|
ConvertString(FALSE,
|
|
pdoiA->tszName, pdoi->tszName, cA(pdoi->tszName));
|
|
pdoi->guidType = pdoiA->guidType;
|
|
pdoi->dwOfs = pdoiA->dwOfs;
|
|
pdoi->dwType = pdoiA->dwType;
|
|
pdoi->dwFlags = pdoiA->dwFlags;
|
|
pdoi->dwSize = sizeof(DIDEVICEOBJECTINSTANCE_DX3);
|
|
pdoi->wReportId = pdoiA->wReportId;
|
|
|
|
if (pdoiA->dwSize > cbX(DIDEVICEOBJECTINSTANCE_DX3A)) {
|
|
pdoi->dwFFMaxForce = pdoiA->dwFFMaxForce;
|
|
pdoi->dwFFForceResolution = pdoiA->dwFFForceResolution;
|
|
pdoi->wCollectionNumber = pdoiA->wCollectionNumber;
|
|
pdoi->wDesignatorIndex = pdoiA->wDesignatorIndex;
|
|
pdoi->wUsagePage = pdoiA->wUsagePage;
|
|
pdoi->wUsage = pdoiA->wUsage;
|
|
pdoi->dwSize = sizeof(DIDEVICEOBJECTINSTANCE);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* GetObjectInfo
|
|
*
|
|
* Do a GetObjectInfo with character set conversion.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
HRESULT EXTERNAL
|
|
GetObjectInfo(PDEVDLGINFO pddi, LPDIDEVICEOBJECTINSTANCE pdoi,
|
|
DWORD dwObj, DWORD dwHow)
|
|
{
|
|
HRESULT hres;
|
|
union {
|
|
DIDEVICEOBJECTINSTANCEA doiA;
|
|
DIDEVICEOBJECTINSTANCEW doiW;
|
|
} u;
|
|
|
|
if (IsUnicodeDidc(pddi->didcItf)) {
|
|
if (g_dwDIVer > 0x0300) {
|
|
u.doiW.dwSize = cbX(u.doiW);
|
|
} else {
|
|
u.doiW.dwSize = cbX(DIDEVICEOBJECTINSTANCE_DX3W);
|
|
}
|
|
} else {
|
|
if (g_dwDIVer > 0x0300) {
|
|
u.doiA.dwSize = cbX(u.doiA);
|
|
} else {
|
|
u.doiA.dwSize = cbX(DIDEVICEOBJECTINSTANCE_DX3A);
|
|
}
|
|
}
|
|
|
|
hres = IDirectInputDevice_GetObjectInfo(pddi->pdid, (PV)&u,
|
|
dwObj, dwHow);
|
|
|
|
if (SUCCEEDED(hres)) {
|
|
ConvertDoi(pddi, pdoi, &u);
|
|
hres = S_OK;
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* ConvertDdi
|
|
*
|
|
* Convert the pvDdi into the local character set.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
void EXTERNAL
|
|
ConvertDdi(PDEVDLGINFO pddi, LPDIDEVICEINSTANCE pinst, LPCVOID pvDdi)
|
|
{
|
|
if (IsUnicodeDidc(pddi->didcItf)) {
|
|
LPCDIDEVICEINSTANCEW pinstW = pvDdi;
|
|
|
|
ConvertString(TRUE,
|
|
pinstW->tszInstanceName,
|
|
pinst->tszInstanceName, cA(pinst->tszInstanceName));
|
|
ConvertString(TRUE,
|
|
pinstW->tszProductName,
|
|
pinst->tszProductName, cA(pinst->tszProductName));
|
|
|
|
pinst->guidInstance = pinstW->guidInstance;
|
|
pinst->guidProduct = pinstW->guidProduct;
|
|
pinst->dwDevType = pinstW->dwDevType;
|
|
pinst->dwSize = sizeof(DIDEVICEINSTANCE_DX3);
|
|
|
|
if (pinstW->dwSize > cbX(DIDEVICEINSTANCE_DX3W)) {
|
|
pinst->guidFFDriver = pinstW->guidFFDriver;
|
|
pinst->wUsagePage = pinstW->wUsagePage;
|
|
pinst->wUsage = pinstW->wUsage;
|
|
pinst->dwSize = sizeof(DIDEVICEINSTANCE);
|
|
}
|
|
|
|
} else {
|
|
LPCDIDEVICEINSTANCEA pinstA = pvDdi;
|
|
|
|
ConvertString(FALSE,
|
|
pinstA->tszInstanceName,
|
|
pinst->tszInstanceName, cA(pinst->tszInstanceName));
|
|
ConvertString(FALSE,
|
|
pinstA->tszProductName,
|
|
pinst->tszProductName, cA(pinst->tszProductName));
|
|
|
|
pinst->guidInstance = pinstA->guidInstance;
|
|
pinst->guidProduct = pinstA->guidProduct;
|
|
pinst->dwDevType = pinstA->dwDevType;
|
|
pinst->dwSize = sizeof(DIDEVICEINSTANCE_DX3);
|
|
|
|
if (pinstA->dwSize > cbX(DIDEVICEINSTANCE_DX3A)) {
|
|
pinst->guidFFDriver = pinstA->guidFFDriver;
|
|
pinst->wUsagePage = pinstA->wUsagePage;
|
|
pinst->wUsage = pinstA->wUsage;
|
|
pinst->dwSize = sizeof(DIDEVICEINSTANCE);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* GetDeviceInfo
|
|
*
|
|
* Do a GetDeviceInfo with character set conversion.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
HRESULT EXTERNAL
|
|
GetDeviceInfo(PDEVDLGINFO pddi, LPDIDEVICEINSTANCE pinst)
|
|
{
|
|
HRESULT hres;
|
|
union {
|
|
DIDEVICEINSTANCEA ddiA;
|
|
DIDEVICEINSTANCEW ddiW;
|
|
} u;
|
|
|
|
if (IsUnicodeDidc(pddi->didcItf)) {
|
|
if (g_dwDIVer > 0x0300) {
|
|
u.ddiW.dwSize = cbX(u.ddiW);
|
|
} else {
|
|
u.ddiW.dwSize = cbX(DIDEVICEINSTANCE_DX3W);
|
|
}
|
|
} else {
|
|
if (g_dwDIVer > 0x0300) {
|
|
u.ddiA.dwSize = cbX(u.ddiA);
|
|
} else {
|
|
u.ddiA.dwSize = cbX(DIDEVICEINSTANCE_DX3A);
|
|
}
|
|
}
|
|
|
|
hres = IDirectInputDevice_GetDeviceInfo(pddi->pdid, (PV)&u);
|
|
|
|
if (SUCCEEDED(hres)) {
|
|
ConvertDdi(pddi, pinst, &u);
|
|
hres = S_OK;
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* ConvertEffi
|
|
*
|
|
* Convert the pvEffi into the local character set.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
void EXTERNAL
|
|
ConvertEffi(PDEVDLGINFO pddi, LPDIEFFECTINFO pei, LPCVOID pvEffi)
|
|
{
|
|
LPCDIEFFECTINFOW peiW = pvEffi;
|
|
LPCDIEFFECTINFOA peiA = pvEffi;
|
|
LPCVOID pvStr;
|
|
|
|
if (IsUnicodeDidc(pddi->didcItf)) {
|
|
pvStr = peiW->tszName;
|
|
} else {
|
|
pvStr = peiA->tszName;
|
|
}
|
|
|
|
ConvertString(IsUnicodeDidc(pddi->didcItf),
|
|
pvStr, pei->tszName, cA(pei->tszName));
|
|
|
|
pei->guid = peiA->guid;
|
|
pei->dwEffType = peiA->dwEffType;
|
|
pei->dwStaticParams = peiA->dwStaticParams;
|
|
pei->dwDynamicParams= peiA->dwDynamicParams;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* GetEffectInfo
|
|
*
|
|
* Do a GetEffectInfo with character set conversion.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
HRESULT EXTERNAL
|
|
GetEffectInfo(PDEVDLGINFO pddi, LPDIEFFECTINFO pei, REFGUID rguid)
|
|
{
|
|
HRESULT hres;
|
|
union {
|
|
DIEFFECTINFOA deiA;
|
|
DIEFFECTINFOW deiW;
|
|
} u;
|
|
|
|
if (IsUnicodeDidc(pddi->didcItf)) {
|
|
u.deiW.dwSize = cbX(u.deiW);
|
|
} else {
|
|
u.deiA.dwSize = cbX(u.deiA);
|
|
}
|
|
|
|
hres = IDirectInputDevice2_GetEffectInfo(pddi->pdid2, (PV)&u, rguid);
|
|
|
|
if (SUCCEEDED(hres)) {
|
|
ConvertEffi(pddi, pei, &u);
|
|
hres = S_OK;
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* StringFromGuid
|
|
*
|
|
*****************************************************************************/
|
|
|
|
void EXTERNAL
|
|
StringFromGuid(LPTSTR ptsz, REFGUID rclsid)
|
|
{
|
|
wsprintf(ptsz,
|
|
TEXT("{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}"),
|
|
rclsid->Data1, rclsid->Data2, rclsid->Data3,
|
|
rclsid->Data4[0], rclsid->Data4[1],
|
|
rclsid->Data4[2], rclsid->Data4[3],
|
|
rclsid->Data4[4], rclsid->Data4[5],
|
|
rclsid->Data4[6], rclsid->Data4[7]);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* MapGUID
|
|
*
|
|
* Convert a GUID to a string, using a friendly name if possible.
|
|
*
|
|
* ptszBuf must be large enough to hold a stringized GUID.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
#pragma BEGIN_CONST_DATA
|
|
|
|
extern GUID GUID_HIDClass;
|
|
|
|
GUID GUID_Null;
|
|
|
|
GUIDMAP c_rggm[] = {
|
|
{ &GUID_XAxis, "GUID_XAxis", },
|
|
{ &GUID_YAxis, "GUID_YAxis", },
|
|
{ &GUID_ZAxis, "GUID_ZAxis", },
|
|
{ &GUID_RxAxis, "GUID_RxAxis", },
|
|
{ &GUID_RyAxis, "GUID_RyAxis", },
|
|
{ &GUID_RzAxis, "GUID_RzAxis", },
|
|
{ &GUID_Slider, "GUID_Slider", },
|
|
{ &GUID_Button, "GUID_Button", },
|
|
{ &GUID_Key, "GUID_Key", },
|
|
{ &GUID_POV, "GUID_POV", },
|
|
{ &GUID_Unknown, "GUID_Unknown", },
|
|
{ &GUID_SysMouse, "GUID_SysMouse" },
|
|
{ &GUID_SysKeyboard, "GUID_SysKeyboard" },
|
|
{ &GUID_Joystick, "GUID_Joystick", },
|
|
{ &GUID_Unknown, "GUID_Unknown", },
|
|
{ &GUID_ConstantForce,"GUID_ConstantForce", },
|
|
{ &GUID_RampForce, "GUID_RampForce", },
|
|
{ &GUID_Square, "GUID_Square", },
|
|
{ &GUID_Sine, "GUID_Sine", },
|
|
{ &GUID_Triangle, "GUID_Triangle", },
|
|
{ &GUID_SawtoothUp, "GUID_SawtoothUp", },
|
|
{ &GUID_SawtoothDown, "GUID_SawtoothDown", },
|
|
{ &GUID_Spring, "GUID_Spring", },
|
|
{ &GUID_Damper, "GUID_Damper", },
|
|
{ &GUID_Inertia, "GUID_Inertia", },
|
|
{ &GUID_Friction, "GUID_Friction", },
|
|
{ &GUID_CustomForce, "GUID_CustomForce", },
|
|
{ &GUID_Null, "GUID_NULL", },
|
|
{ &GUID_HIDClass, "GUID_HIDClass", },
|
|
};
|
|
|
|
LPCTSTR EXTERNAL
|
|
MapGUID(REFGUID rguid, LPTSTR ptszBuf)
|
|
{
|
|
int igm;
|
|
|
|
for (igm = 0; igm < cA(c_rggm); igm++) {
|
|
if (IsEqualGUID(rguid, c_rggm[igm].rguid)) {
|
|
return c_rggm[igm].ptsz;
|
|
}
|
|
}
|
|
|
|
StringFromGuid(ptszBuf, rguid);
|
|
|
|
return ptszBuf;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* ProbeDinputVersion
|
|
*
|
|
* Snoop around to determine what version of DirectInput is available.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
void INTERNAL
|
|
ProbeDinputVersion(void)
|
|
{
|
|
IDirectInput *pdi;
|
|
HRESULT hres;
|
|
|
|
/*
|
|
* For safety's sake, start with DirectX 3.0 and gradually
|
|
* work upwards.
|
|
*/
|
|
g_dwDIVer = 0x0300;
|
|
hres = DirectInputCreate(g_hinst, 0x0300, (PVOID)&pdi, 0);
|
|
|
|
if (SUCCEEDED(hres)) {
|
|
|
|
/*
|
|
* Probe upward to see what version of DirectX is supported.
|
|
*/
|
|
if (SUCCEEDED(IDirectInput_Initialize(pdi, g_hinst,
|
|
DIRECTINPUT_VERSION))) {
|
|
g_dwDIVer = DIRECTINPUT_VERSION;
|
|
|
|
}
|
|
|
|
IDirectInput_Release(pdi);
|
|
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Globals
|
|
*
|
|
*****************************************************************************/
|
|
|
|
HINSTANCE g_hinst;
|
|
HCURSOR g_hcurWait;
|
|
HCURSOR g_hcurStarting;
|
|
DWORD g_dwDIVer;
|
|
#ifdef DEBUG
|
|
TCHAR g_tszInvalid[128];
|
|
#endif
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Entry
|
|
*
|
|
*****************************************************************************/
|
|
|
|
void __cdecl
|
|
Entry(void)
|
|
{
|
|
g_hcurWait = LoadCursor(0, IDC_WAIT);
|
|
g_hcurStarting = LoadCursor(0, IDC_APPSTARTING);
|
|
g_hinst = GetModuleHandle(0);
|
|
|
|
#ifdef DEBUG
|
|
LoadString(g_hinst, IDS_INVALID, g_tszInvalid, cA(g_tszInvalid));
|
|
#endif
|
|
|
|
Checklist_Init();
|
|
ProbeDinputVersion();
|
|
if (SUCCEEDED(CoInitialize(0))) {
|
|
DialogBox(g_hinst, MAKEINTRESOURCE(IDD_MAIN), 0, Diq_DlgProc);
|
|
CoUninitialize();
|
|
}
|
|
|
|
Checklist_Term();
|
|
ExitProcess(0);
|
|
}
|