windows-nt/Source/XPSP1/NT/multimedia/directx/gamectrl/default/test.cpp
2020-09-26 16:20:57 +08:00

1574 lines
49 KiB
C++

//===========================================================================
// TEST.CPP
//
// Functions:
// Test_DlgProc()
// DoJoyMove()
// DoTestButtons()
// DoTestPOV()
// DrawCross()
// DisplayAvailableButtons()
// JoyError()
// DisplayAvailablePOVs()
// SetOEMWindowText()
//
//===========================================================================
// This is necessary for UnregisterDeviceNotification!
#if (WINVER < 0x0500)
#undef WINVER
#define WINVER 0x0500
#endif
#include "cplsvr1.h"
#include <initguid.h>
#include <winuser.h> // For RegisterDeviceNotification stuff!
#include <dbt.h> // for DBT_ defines!!!
#include <hidclass.h>
#include "dicputil.h"
#include "resource.h"
#include "pov.h"
#include "assert.h"
#include <regstr.h> // for REGSTR_VAL_'s below
#include <commctrl.h> // for CProgressCtrl!
#include <shlwapi.h> // for Str... functions!
#include <malloc.h> // _alloca
#include "Gradient.h" // for Gradient Fill Slider!
#ifndef LONG2POINT
#define LONG2POINT(l, pt) ((pt).x = (SHORT)LOWORD(l), (pt).y = (SHORT)HIWORD(l))
#endif // LONG2POINT
// local functions for services exclusive to this module!
static void DisplayAvailablePOVs ( const HWND hWndToolTip, const HWND hDlg, BYTE nPOVs );
static void DisplayAvailableButtons( const HWND hWndToolTip, const HWND hDlg, const int nNumButtons );
static void DisplayAvailableAxisTest(const HWND hWndToolTip, const HWND hDlg, BYTE nAxisFlags, LPDIRECTINPUTDEVICE2 pdiDevice2);
static void DoTestButtons ( const HWND hDlg, PBYTE pbButtons, int nButtons );
static short JoyError ( const HWND hDlg );
static BOOL SetDeviceRanges ( const HWND hDlg, LPDIRECTINPUTDEVICE2 pdiDevice2, BYTE nAxis );
static DWORD DecodeAxisPOV( DWORD dwVal );
// Local defines
#define DELTA 5
#define ID_JOY_TIMER 2002
#define TIMER_INTERVAL 45 // time between polls in milliseconds
#define MAX_SLIDER_POS 100
#define MIN_SLIDER_POS 0
#define FORCE_POV_REFRESH 254
#define ACTIVE_COLOR RGB(255,0,0)
#define INACTIVE_COLOR RGB(128,0,0)
extern BOOL bDlgCentered;
extern BYTE nStatic;
extern CDIGameCntrlPropSheet_X *pdiCpl;
extern HINSTANCE ghInst;
BOOL bGradient;
static HWND ProgWnd[NUM_WNDS];
static CGradientProgressCtrl *pProgs[NUM_WNDS];
static HPEN hTextPen;
static HPEN hWinPen;
LPDIJOYSTATE lpDIJoyState;
extern HICON hIconArray[2];
//===========================================================================
// Test_DlgProc
//
// Parameters:
// HWND hWnd - handle to dialog window
// UINT uMsg - dialog message
// WPARAM wParam - message specific data
// LPARAM lParam - message specific data
//
// Returns: BOOL
//
//===========================================================================
BOOL CALLBACK Test_DlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
static LPDIRECTINPUTDEVICE2 pdiDevice2;
static PVOID hNotifyDevNode;
static HWND hWndToolTip;
static BYTE nAxis;
switch( uMsg ) {
/*
#ifdef _UNICODE
case WM_DEVICECHANGE:
if ((UINT)wParam == DBT_DEVICEREMOVECOMPLETE)
{
if (nStatic & CALIBRATING)
break;
pdiDevice2->Unacquire();
if (FAILED(pdiDevice2->Acquire()))
{
KillTimer(hWnd, ID_JOY_TIMER);
Error(hWnd, (short)IDS_JOYREADERROR, (short)IDS_JOYUNPLUGGED);
// if you call this function you will hang up the system for 30 seconds or more!!!
if (hNotifyDevNode)
UnregisterDeviceNotification(hNotifyDevNode);
::PostMessage(GetParent(hWnd), WM_COMMAND, IDOK, 0);
}
}
break;
#endif
*/
case WM_ACTIVATEAPP:
if( wParam ) {
pdiDevice2->Acquire();
// Hack for bug #228798
if( lpDIJoyState ) {
// This is to refresh the cross hair...
lpDIJoyState->lX+=1;
DoJoyMove( hWnd, nAxis );
// This is to refresh the POV
if( pdiCpl->GetStateFlags()->nPOVs )
DoTestPOV(FORCE_POV_REFRESH, lpDIJoyState->rgdwPOV, hWnd);
}
SetTimer( hWnd, ID_JOY_TIMER, TIMER_INTERVAL, NULL);
} else {
KillTimer(hWnd, ID_JOY_TIMER);
pdiDevice2->Unacquire();
}
break;
case WM_LBUTTONDOWN:
// Click Drag service for PropSheets!
PostMessage(GetParent(hWnd), WM_NCLBUTTONDOWN, (WPARAM)HTCAPTION, lParam);
break;
// OnHelp
case WM_HELP:
KillTimer(hWnd, ID_JOY_TIMER);
OnHelp(lParam);
SetTimer( hWnd, ID_JOY_TIMER, TIMER_INTERVAL, NULL);
return(TRUE);
// OnContextMenu
case WM_CONTEXTMENU:
KillTimer(hWnd, ID_JOY_TIMER);
OnContextMenu(wParam);
SetTimer( hWnd, ID_JOY_TIMER, TIMER_INTERVAL, NULL);
return(TRUE);
// OnInit
case WM_INITDIALOG:
// get ptr to our object
if( !pdiCpl )
pdiCpl = (CDIGameCntrlPropSheet_X*)((LPPROPSHEETPAGE)lParam)->lParam;
hTextPen = hWinPen = NULL;
// Establish if you have enough colours to display the gradient fill scroll bar!
{
HDC hDC = ::GetWindowDC(hWnd);
if( hDC ) { // Prefix Whistler Bug#45099
bGradient = (BOOL)(GetDeviceCaps(hDC, NUMCOLORS) < 0);
::ReleaseDC(hWnd, hDC);
}
}
// load the up and down states!
hIconArray[0] = (HICON)LoadImage(ghInst, (PTSTR)IDI_BUTTONON, IMAGE_ICON, 0, 0, NULL);
assert (hIconArray[0]);
hIconArray[1] = (HICON)LoadImage(ghInst, (PTSTR)IDI_BUTTONOFF, IMAGE_ICON, 0, 0, NULL);
assert (hIconArray[1]);
// initialize DirectInput
if( FAILED(InitDInput(GetParent(hWnd), pdiCpl)) ) {
Error(hWnd, (short)IDS_INTERNAL_ERROR, (short)IDS_NO_DIJOYCONFIG);
// Fix #108983 NT, Remove Flash on Error condition.
SetWindowPos(::GetParent(hWnd), HWND_BOTTOM, 0, 0, 0, 0, SWP_HIDEWINDOW);
PostMessage(GetParent(hWnd), WM_SYSCOMMAND, SC_CLOSE, 0);
return(FALSE);
}
// Get the device2 interface pointer
pdiCpl->GetDevice(&pdiDevice2);
nAxis = pdiCpl->GetStateFlags()->nAxis;
// Set The scale for the Device Range!!!
SetDeviceRanges(hWnd, pdiDevice2, nAxis);
LPDIRECTINPUTJOYCONFIG pdiJoyConfig;
pdiCpl->GetJoyConfig(&pdiJoyConfig);
// Create the Pens for X/Y axis!
CreatePens();
// Create ToolTip window!
hWndToolTip = CreateWindowEx( 0, TOOLTIPS_CLASS, NULL, WS_POPUP | TTS_ALWAYSTIP,
CW_USEDEFAULT, CW_USEDEFAULT, 10, 10, hWnd, NULL, ghInst, NULL);
// Show the available Axis!
DisplayAvailableAxisTest(hWndToolTip, hWnd, nAxis, pdiDevice2);
DisplayAvailableButtons(hWndToolTip, hWnd, pdiCpl->GetStateFlags()->nButtons);
DisplayAvailablePOVs(hWndToolTip, hWnd, pdiCpl->GetStateFlags()->nPOVs);
lpDIJoyState = new (DIJOYSTATE);
assert(lpDIJoyState);
ZeroMemory(lpDIJoyState, sizeof(DIJOYSTATE));
// Clear the Static vars in DoJoyMove!
DoJoyMove(hWnd, nAxis);
// Center the Dialog!
// If it's not been centered!
if( !bDlgCentered ) {
SetTitle(hWnd);
CenterDialog(hWnd);
bDlgCentered = TRUE;
}
{
// Get the Type name
LPDIJOYCONFIG_DX5 lpDIJoyConfig = (LPDIJOYCONFIG_DX5)_alloca(sizeof(DIJOYCONFIG_DX5));
ASSERT (lpDIJoyConfig);
ZeroMemory(lpDIJoyConfig, sizeof(DIJOYCONFIG_DX5));
lpDIJoyConfig->dwSize = sizeof(DIJOYCONFIG_DX5);
if( SUCCEEDED(pdiJoyConfig->GetConfig(pdiCpl->GetID(), (LPDIJOYCONFIG)lpDIJoyConfig, DIJC_REGHWCONFIGTYPE)) ) {
if( lpDIJoyConfig->hwc.dwUsageSettings & JOY_US_ISOEM ) {
LPCTSTR pszLabels[] = {
REGSTR_VAL_JOYOEMTESTMOVEDESC,
REGSTR_VAL_JOYOEMTESTMOVECAP,
REGSTR_VAL_JOYOEMTESTBUTTONCAP,
REGSTR_VAL_JOYOEMPOVLABEL,
REGSTR_VAL_JOYOEMTESTWINCAP};
const short nControlIDs[] = {
IDC_TEXT_AXESHELP,
IDC_AXISGRP,
IDC_GROUP_BUTTONS,
IDC_GROUP_POV,
0};
SetOEMWindowText(hWnd, nControlIDs, pszLabels, lpDIJoyConfig->wszType, pdiJoyConfig, (BYTE)(sizeof(nControlIDs)/sizeof(short))-1);
}
bPolledPOV = (lpDIJoyConfig->hwc.hws.dwFlags & JOY_HWS_HASPOV) && (lpDIJoyConfig->hwc.hws.dwFlags & JOY_HWS_POVISPOLL);
CalibratePolledPOV( &lpDIJoyConfig->hwc );
}
#ifdef _UNICODE
// Set up the Device Notification
// Removed per Om...
//RegisterForDevChange(hWnd, &hNotifyDevNode);
#endif
}
break; // end of WM_INITDIALOG
// OnTimer
case WM_TIMER:
if( SUCCEEDED(DIUtilPollJoystick(pdiDevice2, lpDIJoyState)) ) {
if( nAxis )
DoJoyMove( hWnd, nAxis );
if( pdiCpl->GetStateFlags()->nButtons )
DoTestButtons( hWnd, lpDIJoyState->rgbButtons, pdiCpl->GetStateFlags()->nButtons );
if( pdiCpl->GetStateFlags()->nPOVs )
DoTestPOV( pdiCpl->GetStateFlags()->nPOVs, lpDIJoyState->rgdwPOV, hWnd );
} else {
KillTimer(hWnd, ID_JOY_TIMER);
pdiDevice2->Unacquire();
if( JoyError( hWnd ) == IDRETRY ) {
pdiDevice2->Acquire();
SetTimer( hWnd, ID_JOY_TIMER, TIMER_INTERVAL, NULL);
} else {
// Send a message back to the CPL to update list, as it may have changed!
::PostMessage(GetParent(hWnd), WM_COMMAND, IDOK, 0);
}
}
break; // end of WM_TIMER
// All this has to be done because WM_MOUSEMOVE doesn't get sent to static text!
case WM_MOUSEMOVE:
if( hWndToolTip ) {
POINT pt;
LONG2POINT(lParam, pt);
HWND hChildWnd = ::ChildWindowFromPoint(hWnd, pt);
static HWND hPrev;
if( hChildWnd != hPrev && hChildWnd !=NULL ) {
switch( GetDlgCtrlID(hChildWnd) ) {
case IDC_JOYLIST1_LABEL:
case IDC_JOYLIST2_LABEL:
case IDC_JOYLIST3_LABEL:
case IDC_JOYLIST4_LABEL:
case IDC_JOYLIST5_LABEL:
case IDC_JOYLIST6_LABEL:
case IDC_JOYLIST7_LABEL:
if( IsWindowVisible(hChildWnd) ) {
MSG msg;
//we need to fill out a message structure and pass it to the tooltip
//with the TTM_RELAYEVENT message
msg.hwnd = hWnd;
msg.message = uMsg;
msg.wParam = wParam;
msg.lParam = lParam;
msg.time = GetMessageTime();
GetCursorPos(&msg.pt);
::SendMessage(hWndToolTip, TTM_RELAYEVENT, 0, (LPARAM)&msg);
}
break;
// We don't need to trap for anything else, as the rest are TTF_SUBCLASS'd
default:
break;
}
// store the last one so we don't have to do this again...
hPrev = hChildWnd;
}
}
break;
// OnDestroy
case WM_DESTROY:
bDlgCentered = FALSE;
KillTimer(hWnd, ID_JOY_TIMER);
// Delete the button icons...
DestroyIcon(hIconArray[0]);
DestroyIcon(hIconArray[1]);
// Kill pProgs
if( bGradient ) {
BYTE nAxisCounter = MAX_AXIS - 2;
BYTE nTmpFlags = nAxis;
// Clear the X and Y flags... they don't have progress controls
// associated with them!
nTmpFlags &= ~(HAS_X | HAS_Y);
while( nTmpFlags ) {
if( nTmpFlags & (HAS_Z<<nAxisCounter) ) {
delete (pProgs[nAxisCounter]);
pProgs[nAxisCounter] = 0;
nTmpFlags &= ~(HAS_Z<<nAxisCounter);
}
nAxisCounter--;
}
}
// Destroy the pens!
if (hTextPen)
DeleteObject(hTextPen);
if( hWinPen )
DeleteObject(hWinPen);
if( lpDIJoyState ) {
delete (lpDIJoyState);
lpDIJoyState = NULL;
}
// Make sure you set this to NULL!
pdiDevice2 = NULL;
break; // end of WM_DESTROY
// OnNotify
case WM_NOTIFY:
switch( ((NMHDR*)lParam)->code ) {
case PSN_SETACTIVE:
if( pdiDevice2 ) {
pdiDevice2->Acquire();
// if you have this, you are safe to start the timer!
if( lpDIJoyState )
SetTimer( hWnd, ID_JOY_TIMER, TIMER_INTERVAL, NULL);
lpDIJoyState->lX+=1;
DoJoyMove(hWnd, HAS_X | HAS_Y);
}
break;
case PSN_KILLACTIVE:
KillTimer(hWnd, ID_JOY_TIMER);
pdiDevice2->Unacquire();
break;
}
break; // end of WM_NOTIFY
case WM_SYSCOLORCHANGE:
{
//Destroy old pens.
if (hTextPen)
{
DeleteObject(hTextPen);
hTextPen=NULL;
}
if(hWinPen)
{
DeleteObject(hWinPen);
hWinPen=NULL;
}
//Recreate pens with new colors.
CreatePens();
//Change colors of slider bars.
for(int i=0;i<NUM_WNDS;i++)
{
if(pProgs[i]) {
pProgs[i]->SetBkColor(GetSysColor(COLOR_WINDOW));
}
}
}
break;
}
return(FALSE);
} //*** end Test_DlgProc()
//===========================================================================
// DoJoyMove( HWND hDlg, LPDIJOYSTATE pDIJoyState, int nDrawFlags )
//
// Reports to hDlg state information from pDIJoyState, dwDrawFlags, and pJoyRange;
//
// Parameters:
// HWND hDlg - Handle to Dialog
// LPDIJOYSTATE pDIJoyState - State information about the device
// LPJOYRANGE pJoyRange
//
// Returns: nichts
//
//===========================================================================
void DoJoyMove( const HWND hDlg, BYTE nDrawFlags )
{
if( !::IsWindow(hDlg) ) {
#ifdef _DEBUG
OutputDebugString(TEXT("DoJoyMove: hDlg: Not a valid window!\n"));
#endif
return;
}
if( nDrawFlags == 0 ) {
#ifdef _DEBUG
OutputDebugString(TEXT("DoJoyMove: nDrawFlags is Zero!\n"));
#endif
return;
}
// draw the cross in the XY box if needed
if( (nDrawFlags & HAS_X) || (nDrawFlags & HAS_Y) ) {
static POINTS ptOld = {DELTA,DELTA};
HWND hCtrl = GetDlgItem( hDlg, IDC_JOYLIST1 );
assert(hCtrl);
//RedrawWindow(hCtrl, NULL, NULL, RDW_INVALIDATE | RDW_ERASENOW);
RECT rc;
GetClientRect(hCtrl, &rc);
// The Real Max is rc.bottom-DELTA!
rc.bottom -= DELTA;
// Check for ranges - Y Axis
if( lpDIJoyState->lY > rc.bottom ) {
#ifdef _DEBUG
OutputDebugString(TEXT("GCDEF: DoJoyMove: retrieved Y pos > Max Y pos!\n"));
#endif
lpDIJoyState->lY = rc.bottom;
} else if( lpDIJoyState->lY < DELTA ) {
#ifdef _DEBUG
OutputDebugString(TEXT("GCDEF: DoJoyMove: retrieved Y pos < Min Y pos!\n"));
#endif
lpDIJoyState->lY = DELTA;
}
// Check for ranges - X Axis
if( lpDIJoyState->lX > rc.right ) {
#ifdef _DEBUG
OutputDebugString(TEXT("GCDEF: DoJoyMove: retrieved X pos > Max X pos!\n"));
#endif
lpDIJoyState->lX = rc.right;
} else if( lpDIJoyState->lX < DELTA ) {
#ifdef _DEBUG
OutputDebugString(TEXT("GCDEF: DoJoyMove: retrieved X pos < Min X pos!\n"));
#endif
lpDIJoyState->lX = DELTA;
}
// out with the old...
if( (ptOld.x != (short)lpDIJoyState->lX) || (ptOld.y != (short)lpDIJoyState->lY) ) {
// Sorry... no drawing outside of your RECT!
if( (ptOld.x > (rc.right-DELTA)) || (ptOld.y > rc.bottom) ) {
ptOld.x = ptOld.y = DELTA;
return;
}
DrawCross(hCtrl, &ptOld, COLOR_WINDOW );
ptOld.x = (short)lpDIJoyState->lX;
ptOld.y = (short)lpDIJoyState->lY;
// in with the new...
DrawCross( hCtrl, &ptOld, COLOR_WINDOWTEXT );
}
nDrawFlags &= ~(HAS_X | HAS_Y);
}
// draw Z bar if needed
if( nDrawFlags ) {
if( nDrawFlags & HAS_Z ) {
static BYTE nOldZ; // = MAX_SLIDER_POS+1;
if( lpDIJoyState->lZ != nOldZ ) {
if( bGradient )
pProgs[Z_INDEX]->SetPos(lpDIJoyState->lZ);
::PostMessage(ProgWnd[Z_INDEX], PBM_SETPOS, (WPARAM)abs(lpDIJoyState->lZ - MAX_SLIDER_POS), 0L);
nOldZ = (BYTE)lpDIJoyState->lZ;
}
nDrawFlags &= ~HAS_Z;
}
} else return;
// draw Slider0 bar if needed
if( nDrawFlags ) {
if( nDrawFlags & HAS_SLIDER0 ) {
// Any value > 100, as that's the largest one we'll ever recieve!
static BYTE nOldS0; // = MAX_SLIDER_POS+1;
if( lpDIJoyState->rglSlider[0] != nOldS0 ) {
nOldS0 = (BYTE)lpDIJoyState->rglSlider[0];
if( bGradient )
pProgs[S0_INDEX]->SetPos(lpDIJoyState->rglSlider[0]);
::PostMessage(ProgWnd[S0_INDEX], PBM_SETPOS, (WPARAM)abs(lpDIJoyState->rglSlider[0]-MAX_SLIDER_POS), 0L);
}
nDrawFlags &= ~HAS_SLIDER0;
}
} else return;
// draw Rx bar if needed
if( nDrawFlags ) {
if( nDrawFlags & HAS_RX ) {
static BYTE nOldRx; // = MAX_SLIDER_POS+1;
if( lpDIJoyState->lRx != nOldRx ) {
nOldRx = (BYTE)lpDIJoyState->lRx;
if( bGradient )
pProgs[RX_INDEX]->SetPos(lpDIJoyState->lRx);
::PostMessage(ProgWnd[RX_INDEX], PBM_SETPOS, (WPARAM)abs(lpDIJoyState->lRx - MAX_SLIDER_POS), 0L);
}
nDrawFlags &= ~HAS_RX;
}
} else return;
// draw Ry bar if needed
if( nDrawFlags ) {
if( nDrawFlags & HAS_RY ) {
static BYTE nOldRy; // = MAX_SLIDER_POS+1;
if( lpDIJoyState->lRy != nOldRy ) {
nOldRy = (BYTE)lpDIJoyState->lRy;
if( bGradient )
pProgs[RY_INDEX]->SetPos(lpDIJoyState->lRy);
::PostMessage(ProgWnd[RY_INDEX], PBM_SETPOS, (WPARAM)abs(lpDIJoyState->lRy - MAX_SLIDER_POS), 0L);
}
nDrawFlags &= ~HAS_RY;
}
} else return;
// draw Rz bar if needed
if( nDrawFlags ) {
if( nDrawFlags & HAS_RZ ) {
static BYTE nOldRz; // = MAX_SLIDER_POS+1;
if( lpDIJoyState->lRz != nOldRz ) {
nOldRz = (BYTE)lpDIJoyState->lRz;
if( bGradient )
pProgs[RZ_INDEX]->SetPos(lpDIJoyState->lRz);
::PostMessage(ProgWnd[RZ_INDEX], PBM_SETPOS, (WPARAM)abs(lpDIJoyState->lRz - MAX_SLIDER_POS), 0L);
}
nDrawFlags &= ~HAS_RZ;
}
} else return;
// draw Slider1 bar if needed
if( nDrawFlags ) {
if( nDrawFlags & HAS_SLIDER1 ) {
static BYTE nOldS1; // = MAX_SLIDER_POS+1;
if( lpDIJoyState->rglSlider[1] != nOldS1 ) {
nOldS1 = (BYTE)lpDIJoyState->rglSlider[1];
if( bGradient )
pProgs[S1_INDEX]->SetPos(lpDIJoyState->rglSlider[1]);
::PostMessage(ProgWnd[S1_INDEX], PBM_SETPOS, (WPARAM)abs(lpDIJoyState->rglSlider[1] - MAX_SLIDER_POS), 0L);
}
}
}
} // *** end of DoJoyMove
//===========================================================================
// DoTestButtons( HWND hDlg, PBYTE pbButtons, short nButtons )
//
// Lites whatever button(s) that may be pressed.
//
// Parameters:
// HWND hDlg - Handle to Dialog
// PBYTE pbButtons - Pointer to byte array of buttons and their states
// int dwButtons - Number of buttons on device (per STATEFLAGS struct)
//
// Returns: nichts
//
//===========================================================================
static void DoTestButtons( const HWND hDlg, PBYTE pbButtons, int nButtons )
{
// validate pointer(s)
if( (IsBadReadPtr((void*)pbButtons, sizeof(BYTE))) ) {
#ifdef _DEBUG
OutputDebugString(TEXT("DoTestButtons: Bad Read Pointer argument!\n"));
#endif
return;
}
if( (IsBadWritePtr((void*)pbButtons, sizeof(BYTE))) ) {
#ifdef _DEBUG
OutputDebugString(TEXT("DoTestButtons: Bad Write Pointer argument!\n"));
#endif
return;
}
// Don't worry about the Zero Button condition!
// It's being done in the timer!
static BYTE bLookup[MAX_BUTTONS] = {NULL};
BYTE i = 0;
// Loop threw the buttons looking only at the ones we know we have!
while( nButtons && (nButtons & (HAS_BUTTON1<<i)) ) {
// check for a button press
if( pbButtons[i] != bLookup[i] ) {
// update the button with the proper bitmap
HWND hCtrl = GetDlgItem(hDlg, IDC_TESTJOYBTNICON1+i);
// Set the Extra Info
SetWindowLongPtr(hCtrl, GWLP_USERDATA, (LONG_PTR)(pbButtons[i] & 0x80) ? 1 : 0);
RedrawWindow(hCtrl, NULL, NULL, RDW_INVALIDATE | RDW_ERASENOW);
// update the lookup table
bLookup[i] = pbButtons[i];
}
// strip the button!
nButtons &= ~(HAS_BUTTON1<<i++);
}
} // end of DoTestButtons
//===========================================================================
// DoTestPOV( PDWORD pdwPOV )
//
// Routes a call to SetDegrees to set the degrees to pdwPOV
//
// Parameters:
// PDWORD pdwPOV - degrees at which to display the POV arrow
//
// Returns: nichts
//
//===========================================================================
void DoTestPOV( BYTE nPov, PDWORD pdwPOV, HWND hDlg )
{
// Assume all POV's to be centred at start
// JOY_POVCENTERED is defined as 0xffffffff
static short dwOldPOV[MAX_POVS] = {-1,-1,-1,-1};
BYTE nPovCounter = MAX_POVS-1;
BYTE nPovs = 0;
BOOL bChanged = FALSE;
if( nPov == FORCE_POV_REFRESH ) {
nPovs = 1;
bChanged = TRUE;
} else {
// You Never have to worry about nPov being Zero,
// it is checked before entering this function!
do {
// Be aware that nPov is not just a number... it's a bit mask!
if( nPov & (HAS_POV1<<nPovCounter) ) {
DWORD dwPov = (nPov & HAS_CALIBRATED) ? pdwPOV[nPovCounter] : pdwPOV[nPovCounter];
if( dwOldPOV[nPovCounter] != (int)dwPov ) {
dwOldPOV[nPovCounter] = (dwPov > 36001) ? -1 : (int)dwPov;
bChanged = TRUE;
}
nPovs++;
nPov &= ~(HAS_POV1<<nPovCounter);
}
} while( nPovCounter-- && nPov );
}
if( bChanged ) {
SetDegrees(nPovs, dwOldPOV, GetDlgItem(hDlg, IDC_JOYPOV));
}
} // *** end of DoTestPOV
//===========================================================================
// DrawCross( HWND hwnd, LPPOINTS pPoint, short nFlag)
//
// Draws a cross on hwnd at pPoint of type nFlag
//
// Parameters:
// HWND hwnd
// LPPOINTS pPoint
// int nFlag
//
// Returns: nichts
//
//===========================================================================
static void DrawCross(const HWND hwnd, LPPOINTS pPoint, short nFlag)
{
assert(hwnd);
HDC hdc = GetDC( hwnd );
HPEN holdpen = (struct HPEN__ *) SelectObject( hdc, (nFlag == COLOR_WINDOW) ? hWinPen : hTextPen );
MoveToEx( hdc, pPoint->x-(DELTA-1), pPoint->y, NULL);
LineTo( hdc, pPoint->x+DELTA, pPoint->y );
MoveToEx( hdc, pPoint->x, pPoint->y-(DELTA-1), NULL );
LineTo( hdc, pPoint->x, pPoint->y+DELTA );
SelectObject( hdc, holdpen );
ReleaseDC( hwnd, hdc );
} // *** end of DrawCross
void CreatePens( void )
{
// We always create both at the same time so checking one is sufficient!
if( hTextPen == NULL ) {
LOGPEN LogPen;
LogPen.lopnStyle = PS_SOLID;
LogPen.lopnWidth.x = LogPen.lopnWidth.y = 0;
LogPen.lopnColor = GetSysColor( COLOR_WINDOW );
hWinPen = CreatePenIndirect(&LogPen);
LogPen.lopnColor = GetSysColor( COLOR_WINDOWTEXT );
hTextPen = CreatePenIndirect(&LogPen);
}
}
//===========================================================================
// DisplayAvailableButtons(HWND hWnd, int nNumButtons)
//
// Removes buttons not found on the device!
//
//
// Parameters:
// HWND hDlg - Dialog handle
// int nNumButtons - Number of buttons to display
//
// Returns:
//
//===========================================================================
void DisplayAvailableButtons(const HWND hWndToolTip, const HWND hDlg, const int nButtonFlags)
{
LPTOOLINFO pToolInfo;
LPTSTR lpStr;
if( nButtonFlags ) {
if( hWndToolTip ) {
pToolInfo = new (TOOLINFO);
ASSERT (pToolInfo);
lpStr = new (TCHAR[STR_LEN_32]);
ASSERT(lpStr);
ZeroMemory(pToolInfo, sizeof(TOOLINFO));
pToolInfo->cbSize = sizeof(TOOLINFO);
pToolInfo->uFlags = 0;
pToolInfo->hwnd = hDlg;
::SendDlgItemMessage(hDlg, IDC_GROUP_BUTTONS, WM_GETTEXT, (WPARAM)STR_LEN_32, (LPARAM)lpStr);
pToolInfo->lpszText = lpStr;
}
}
HWND hCtrl;
// Show the ones we have...
// Destroy the ones we don't!
BYTE i = MAX_BUTTONS;
do {
hCtrl = GetDlgItem(hDlg, IDC_TESTJOYBTNICON1+(--i));
if( (nButtonFlags & HAS_BUTTON1<<i) && pToolInfo ) {
// Add the Control to the tool!
pToolInfo->uFlags = TTF_IDISHWND | TTF_SUBCLASS;
pToolInfo->uId = (ULONG_PTR) hCtrl;
// Add the control!
::SendMessage(hWndToolTip, TTM_ADDTOOL, 0, (LPARAM)pToolInfo);
continue;
}
DestroyWindow(hCtrl);
} while( i );
if( nButtonFlags ) {
if( lpStr )
delete[] (lpStr);
if( pToolInfo )
delete (pToolInfo);
} else {
// don't forget to remove the groupe!
hCtrl = GetDlgItem(hDlg, IDC_GROUP_BUTTONS);
DestroyWindow(hCtrl);
}
} //*** end DisplayAvailableButtons()
//===========================================================================
// JoyError(HWND hwnd)
//
// Displays the "Device Not Connected"
//
// Parameters:
// HWND hwnd - window handle
//
// Returns: rc - User selection from MessageBox
//
//===========================================================================
short JoyError( const HWND hwnd )
{
assert(hwnd);
LPTSTR lptszTitle = (LPTSTR)_alloca(sizeof(TCHAR[STR_LEN_32]));
assert (lptszTitle);
short rc;
if( LoadString(ghInst, IDS_JOYREADERROR, lptszTitle, STR_LEN_32) ) {
LPTSTR lptszMsg = (LPTSTR)_alloca(sizeof(TCHAR[STR_LEN_128]));
assert(lptszMsg);
if( LoadString(ghInst, IDS_JOYUNPLUGGED, lptszMsg, STR_LEN_128) ) {
rc = (short)MessageBox( hwnd, lptszMsg, lptszTitle, MB_RETRYCANCEL | MB_ICONERROR );
if( rc == IDCANCEL ) {
// terminate the dialog if we give up
PostMessage( GetParent(hwnd), WM_COMMAND, IDCANCEL, 0 );
}
}
}
return(rc);
} // *** end of JoyError
//===========================================================================
// DisplayAvailablePOVs( const HWND hWndToolTip, const HWND hDlg, BYTE nPOVs )
//
// Displays POV window if there are any associated with the device.
//
// Parameters:
// HWND hDlg - window handle
// short nPOVs - number of POVs
//
// Returns: nichts
//
//===========================================================================
static void DisplayAvailablePOVs ( const HWND hWndToolTip, const HWND hDlg, BYTE nPOVs )
{
HWND hwndPOV = GetDlgItem(hDlg, IDC_JOYPOV);
SetWindowPos( hwndPOV, NULL, NULL, NULL, NULL, NULL,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | ((nPOVs) ? SWP_SHOWWINDOW : SWP_HIDEWINDOW));
SetWindowPos( GetDlgItem( hDlg, IDC_GROUP_POV ), NULL, NULL, NULL, NULL, NULL,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | ((nPOVs) ? SWP_SHOWWINDOW : SWP_HIDEWINDOW));
if( nPOVs ) {
// Disable RTL flag
SetWindowLongPtr(hwndPOV, GWL_EXSTYLE, GetWindowLongPtr(hwndPOV,GWL_EXSTYLE) & ~WS_EX_LAYOUTRTL );
if( hWndToolTip ) {
LPTOOLINFO pToolInfo = (LPTOOLINFO)_alloca(sizeof(TOOLINFO));
ASSERT (pToolInfo);
LPTSTR lpStr = (LPTSTR)_alloca(sizeof(TCHAR[STR_LEN_32]));
ASSERT (lpStr);
if( pToolInfo && lpStr ) {
ZeroMemory(pToolInfo, sizeof(TOOLINFO));
pToolInfo->cbSize = sizeof(TOOLINFO);
pToolInfo->uFlags = 0;
pToolInfo->hwnd = hDlg;
::SendDlgItemMessage(hDlg, IDC_GROUP_POV, WM_GETTEXT, (WPARAM)STR_LEN_32, (LPARAM)lpStr);
pToolInfo->lpszText = lpStr;
pToolInfo->uFlags = TTF_IDISHWND | TTF_SUBCLASS;
pToolInfo->uId = (ULONG_PTR)hwndPOV;
// Add the control!
::SendMessage(hWndToolTip, TTM_ADDTOOL, 0, (LPARAM)pToolInfo);
}
}
}
} // *** end of DisplayAvailablePOVs
//===========================================================================
// SetOEMWindowText( HWND hDlg, short *nControlIDs, LPTSTR *pszLabels, BYTE nCount )
//
// Retrieves text from registry keys and Displays it in a Dialog Control or title!
//
// Parameters:
// HWND hDlg - Handle to dialog where strings are to be sent
// nControlIDs - Pointer to array of Dialog Item ID's
// Zero may be used if you want the Title!
// pszLabels - Pointer to array of Registry Keys to read
// nCount - Number of ellements in the array
//
// Returns: nichts
//
//===========================================================================
void SetOEMWindowText ( const HWND hDlg, const short *nControlIDs, LPCTSTR *pszLabels, LPCWSTR wszType, LPDIRECTINPUTJOYCONFIG pdiJoyConfig, BYTE nCount )
{
if( nCount == 0 ) {
#ifdef _DEBUG
OutputDebugString(TEXT("JOY.CPL: Test.cpp: SetOEMWindowText: nCount is Zero!\n"));
#endif
return;
}
// validate nControlIDs pointer
if( IsBadReadPtr((void*)nControlIDs, sizeof(short)) ) {
#ifdef _DEBUG
OutputDebugString(TEXT("JOY.CPL: Test.cpp: SetOEMWindowText: nControlIDs is not a valid Read Pointer!\n"));
#endif
return;
}
// validate pointers
if( IsBadReadPtr((void*)pszLabels, sizeof(TCHAR)) ) {
#ifdef _DEBUG
OutputDebugString(TEXT("JOY.CPL: Test.cpp: SetOEMWindowText: pszLabels is not a valid Read Pointer!\n"));
#endif
return;
}
HKEY hKey;
pdiJoyConfig->Acquire();
// Open the TypeKey
if( FAILED(pdiJoyConfig->OpenTypeKey( wszType, KEY_ALL_ACCESS, &hKey)) ) {
#ifdef _DEBUG
OutputDebugString(TEXT("Test.cpp: SetOEMWindowText: OpenTypeKey FAILED!\n"));
#endif
return;
}
DWORD dwCount = MAX_STR_LEN;
LPTSTR pszBuff = (LPTSTR)_alloca(sizeof(TCHAR[MAX_STR_LEN]));
assert(pszBuff);
DWORD dwType = REG_SZ;
do {
if( RegQueryValueEx( hKey, pszLabels[nCount], NULL, &dwType, (CONST LPBYTE)pszBuff, &dwCount ) == ERROR_SUCCESS ) {
// This is because RegQueryValueEx returns dwCount size as the size
// of the terminating char if the label is found w/o a string!
if( dwCount > sizeof(TCHAR) ) {
if( nControlIDs[nCount] )
::SendMessage(GetDlgItem(hDlg, nControlIDs[nCount]), WM_SETTEXT, 0, (LPARAM)(LPCTSTR)pszBuff);
else
::SendMessage(GetParent(hDlg), WM_SETTEXT, 0, (LPARAM)(LPCTSTR)pszBuff);
}
#ifdef _DEBUG
else OutputDebugString(TEXT("Test.cpp: SetOEMWindowText: ReqQueryValueEx failed to find Registry string!\n"));
#endif
}
dwCount = MAX_STR_LEN;
} while( nCount-- );
RegCloseKey(hKey);
} // *** end of SetOEMWindowText
//===========================================================================
// DisplayAvailableAxisTest(HWND hDlg, BYTE nAxisFlags, LPDIRECTINPUTDEVICE2 pdiDevice2)
//
// Displays the number and names of the device Axis in the provided dialog.
// This EXPECTS that the controls are not visible by default!
//
// Parameters:
// HWND hDlg - Dialog handle
// BYTE nAxisFlags - Flags for number of Axis to display
//
// Returns:
//
//===========================================================================
void DisplayAvailableAxisTest(const HWND hWndToolTip, const HWND hDlg, BYTE nAxisFlags, LPDIRECTINPUTDEVICE2 pdiDevice2)
{
if( nAxisFlags == 0 ) {
DestroyWindow(GetDlgItem(hDlg, IDC_AXISGRP));
#ifdef _DEBUG
OutputDebugString(TEXT("GCDEF.DLL: DisplayAvailableAxis: Number of Axis is 0!\n"));
#endif
return;
}
LPDIDEVICEOBJECTINSTANCE_DX3 pDevObjInst = new (DIDEVICEOBJECTINSTANCE_DX3);
assert (pDevObjInst);
pDevObjInst->dwSize = sizeof(DIDEVICEOBJECTINSTANCE_DX3);
LPTOOLINFO pToolInfo;
if( hWndToolTip ) {
pToolInfo = new (TOOLINFO);
ASSERT (pToolInfo);
ZeroMemory(pToolInfo, sizeof(TOOLINFO));
pToolInfo->cbSize = sizeof(TOOLINFO);
pToolInfo->uFlags = 0;
pToolInfo->hwnd = hDlg;
}
HWND hCtrl;
// X and Y use the same control so they are isolated!
if( (nAxisFlags & HAS_X) || (nAxisFlags & HAS_Y) ) {
HWND hwndXY = GetDlgItem(hDlg, IDC_JOYLIST1);
// Show the Window
SetWindowPos( hwndXY, NULL, NULL, NULL, NULL, NULL,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW);
// Disable RTL flag
SetWindowLongPtr(hwndXY, GWL_EXSTYLE, GetWindowLongPtr(hwndXY,GWL_EXSTYLE) & ~WS_EX_LAYOUTRTL );
hCtrl = GetDlgItem(hDlg, IDC_JOYLIST1_LABEL);
// Show it's text
SetWindowPos( hCtrl, NULL, NULL, NULL, NULL, NULL,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW);
LPTSTR ptszBuff = (LPTSTR)_alloca(sizeof(TCHAR[STR_LEN_64]));
assert (ptszBuff);
ZeroMemory(ptszBuff, sizeof(TCHAR[STR_LEN_64]));
// Set it's text
if( nAxisFlags & HAS_X ) {
if( SUCCEEDED(pdiDevice2->GetObjectInfo((LPDIDEVICEOBJECTINSTANCE)pDevObjInst, DIJOFS_X, DIPH_BYOFFSET)) )
{
int nLen=lstrlen(pDevObjInst->tszName)+1;
if(nLen>STR_LEN_64)
nLen=STR_LEN_64;
StrCpyN(ptszBuff, pDevObjInst->tszName, nLen);
}
// Remove the HAS_X flag
nAxisFlags &= ~HAS_X;
}
if( nAxisFlags & HAS_Y ) {
if( FAILED(pdiDevice2->GetObjectInfo((LPDIDEVICEOBJECTINSTANCE)pDevObjInst, DIJOFS_Y, DIPH_BYOFFSET)) ) {
#ifdef _DEBUG
OutputDebugString(TEXT("GCDEF.DLL: DisplayAvailableAxis: GetObjectInfo Failed to find DIJOFS_Y!\n"));
#endif
}
if( ptszBuff && lstrlen(ptszBuff) ) {
int nLen=STR_LEN_64-lstrlen(ptszBuff);
StrNCat(ptszBuff, TEXT(" / "), nLen);
}
int nLen=STR_LEN_64-lstrlen(ptszBuff);
StrNCat(ptszBuff, pDevObjInst->tszName, nLen);
// Remove the HAS_Y flag
nAxisFlags &= ~HAS_Y;
}
::SendMessage(hCtrl, WM_SETTEXT, 0, (LPARAM)(LPCTSTR)ptszBuff);
// CreateWindow could have failed... if so, no tooltips!
if( hWndToolTip ) {
GetWindowRect(hCtrl, &pToolInfo->rect);
ScreenToClient(GetParent(hDlg), (LPPOINT)&pToolInfo->rect);
ScreenToClient(GetParent(hDlg), ((LPPOINT)&pToolInfo->rect)+1);
pToolInfo->lpszText = ptszBuff;
// Add the Label...
::SendMessage(hWndToolTip, TTM_ADDTOOL, 0, (LPARAM)pToolInfo);
// Add the Control!
pToolInfo->uFlags = TTF_IDISHWND | TTF_SUBCLASS;
pToolInfo->uId = (ULONG_PTR)hwndXY;
// Add the control!
::SendMessage(hWndToolTip, TTM_ADDTOOL, 0, (LPARAM)pToolInfo);
}
}
// if you have additional axis, keep going!
if( nAxisFlags ) {
// Array of supported axis!
DWORD dwOffsetArray[] = {DIJOFS_Z, DIJOFS_RX, DIJOFS_RY, DIJOFS_RZ, DIJOFS_SLIDER(0), DIJOFS_SLIDER(1)};
BYTE nAxisCounter = MAX_AXIS - 2;
// Go 'till you run out of axis!
do {
if( nAxisFlags & (HAS_Z<<nAxisCounter) ) {
// Create and Assign to the global list!
ProgWnd[nAxisCounter] = GetDlgItem(hDlg, nAxisCounter+IDC_JOYLIST2);
ASSERT (ProgWnd[nAxisCounter]);
// Create Gradient Class
if( bGradient ) {
pProgs[nAxisCounter] = new (CGradientProgressCtrl);
assert (pProgs[nAxisCounter]);
// Subclass the Progress Control Window
pProgs[nAxisCounter]->SubclassWindow(ProgWnd[nAxisCounter]);
} else {
// Set the colour
// PBM_SETBARCOLOR is WM_USER+9
::PostMessage(ProgWnd[nAxisCounter], WM_USER+9, 0, (LPARAM)ACTIVE_COLOR);
}
// Show the control... ProgWnd[nAxisCounter]
SetWindowPos( ProgWnd[nAxisCounter], NULL, NULL, NULL, NULL, NULL,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW);
hCtrl = GetDlgItem(hDlg, nAxisCounter+IDC_JOYLIST2_LABEL);
// Now, Show it's text
SetWindowPos( hCtrl, NULL, NULL, NULL, NULL, NULL,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW);
// Get it's text
if( SUCCEEDED(pdiDevice2->GetObjectInfo((LPDIDEVICEOBJECTINSTANCE)pDevObjInst, dwOffsetArray[nAxisCounter], DIPH_BYOFFSET)) ) {
TCHAR tszAxisName[20];
int nLen=lstrlen(pDevObjInst->tszName)+1;
if(nLen>20)
nLen=20;
StrCpyN(tszAxisName, pDevObjInst->tszName, nLen);
if( lstrlen( tszAxisName ) > 4 ) {
tszAxisName[4] = L'.';
tszAxisName[5] = L'.';
tszAxisName[6] = 0;
}
::SendMessage(hCtrl, WM_SETTEXT, 0, (LPARAM)(LPCTSTR)tszAxisName);
// Just in case CreateWindow failed!!!
if( hWndToolTip ) {
GetWindowRect(hCtrl, &pToolInfo->rect);
ScreenToClient(GetParent(hDlg), (LPPOINT)&pToolInfo->rect);
ScreenToClient(GetParent(hDlg), ((LPPOINT)&pToolInfo->rect)+1);
pToolInfo->uFlags = 0;
pToolInfo->lpszText = pDevObjInst->tszName;
// Add the Label...
::SendMessage(hWndToolTip, TTM_ADDTOOL, 0, (LPARAM)pToolInfo);
// Add the Control!
pToolInfo->uFlags = TTF_IDISHWND | TTF_SUBCLASS;
pToolInfo->uId = (ULONG_PTR) ProgWnd[nAxisCounter];
// Now, Add the control!
::SendMessage(hWndToolTip, TTM_ADDTOOL, 0, (LPARAM)pToolInfo);
}
}
// Remove the flag you just hit!
nAxisFlags &= ~(HAS_Z<<nAxisCounter);
}
} while( nAxisCounter-- && nAxisFlags );
}
if( hWndToolTip ) {
if( pToolInfo )
delete (pToolInfo);
}
if( pDevObjInst )
delete (pDevObjInst);
} //*** end of DisplayAvailableAxisTest
//===========================================================================
// BOOL SetDeviceRanges( HWND hDlg, LPDIRECTINPUTDEVICE2 pdiDevice2, BYTE nAxis)
//
// Parameters:
// HWND hDlg - Handle of Dialog containing controls to scale to
// LPDIRECTINPUTDEVICE2 pdiDevice2 - Device2 Interface pointer
// BYTE nAxis - Bit mask of axis ranges to set
//
// Returns: FALSE if failed
//
//===========================================================================
BOOL SetDeviceRanges( const HWND hDlg, LPDIRECTINPUTDEVICE2 pdiDevice2, BYTE nAxis)
{
if( !::IsWindow(hDlg) ) {
#ifdef _DEBUG
OutputDebugString(TEXT("GCDEF: SetDeviceRanges: hDlg: Not a valid window!\n"));
#endif
return(FALSE);
}
// validate pDIDevice2 pointer
if( IsBadReadPtr((void*)pdiDevice2, sizeof(IDirectInputDevice2)) ) {
#ifdef _DEBUG
OutputDebugString(TEXT("GCDEF: SetDeviceRanges: pdiDevice2: Bad Read Pointer argument!\n"));
#endif
return(FALSE);
}
if( !nAxis ) {
#ifdef _DEBUG
OutputDebugString(TEXT("GCDEF: SetDeviceRanges: nAxis is Zero!\n"));
#endif
return(FALSE);
}
LPDIPROPRANGE pDIPropRange = (LPDIPROPRANGE)_alloca(sizeof(DIPROPRANGE));
assert (pDIPropRange);
if( !pDIPropRange ) {
#ifdef _DEBUG
OutputDebugString(TEXT("GCDEF: SetDeviceRanges: Failed to malloc DIPROPDRANGE!\n"));
#endif
return(FALSE);
}
pDIPropRange->diph.dwSize = sizeof(DIPROPRANGE);
pDIPropRange->diph.dwHeaderSize = sizeof(DIPROPHEADER);
pDIPropRange->diph.dwHow = DIPH_BYOFFSET;
BOOL bRet = TRUE;
HWND hCtrl;
RECT rc;
// since X and Y share the same window..
if( (nAxis & HAS_X) || (nAxis & HAS_Y) ) {
hCtrl = GetDlgItem(hDlg, IDC_JOYLIST1);
assert (hCtrl);
GetClientRect( hCtrl, &rc );
// Check if it's X
if( nAxis & HAS_X ) {
pDIPropRange->diph.dwObj = DIJOFS_X;
pDIPropRange->lMin = DELTA;
pDIPropRange->lMax = rc.right-DELTA;
if( FAILED(pdiDevice2->SetProperty(DIPROP_RANGE, &pDIPropRange->diph)) ) {
#ifdef _DEBUG
OutputDebugString(TEXT("GCDEF: SetDeviceRanges: SetProperty Failed to return X axis Ranges!\n"));
#endif
bRet = FALSE;
}
// strip off the bits you just used
nAxis &= ~HAS_X;
}
// Check if it's Y
if( nAxis & HAS_Y ) {
pDIPropRange->diph.dwObj = DIJOFS_Y;
pDIPropRange->lMin = DELTA;
pDIPropRange->lMax = rc.bottom-DELTA;
if( FAILED(pdiDevice2->SetProperty(DIPROP_RANGE, &pDIPropRange->diph)) ) {
#ifdef _DEBUG
OutputDebugString(TEXT("GCDEF: SetDeviceRanges: SetProperty Failed to return Y axis Ranges!\n"));
#endif
bRet = FALSE;
}
// strip off the bits you just used
nAxis &= ~HAS_Y;
}
}
// you've got axes > X & Y...
if( nAxis ) {
const DWORD dwOfset[] = {DIJOFS_Z, DIJOFS_RX, DIJOFS_RY, DIJOFS_RZ, DIJOFS_SLIDER(0), DIJOFS_SLIDER(1)};
// Minus 2 is because we've already done X/Y!
// the third decrement is for the Zero based dwOffset!
BYTE nAxisCounter = MAX_AXIS-3;
// These aren't random!
// These are the default ranges for the CProgressCtrl!!!
pDIPropRange->lMin = MIN_SLIDER_POS;
pDIPropRange->lMax = MAX_SLIDER_POS;
do {
if( nAxis & (HAS_Z<<nAxisCounter) ) {
pDIPropRange->diph.dwObj = dwOfset[nAxisCounter];
VERIFY(SUCCEEDED(pdiDevice2->SetProperty(DIPROP_RANGE, &pDIPropRange->diph)));
// Remove the flag you just hit!
nAxis &= ~(HAS_Z<<nAxisCounter);
}
nAxisCounter--;
} while( nAxis );
}
return(bRet);
}
#ifdef _UNICODE
///////////////////////////////////////////////////////////////////////////////
// FUNCTION: RegisterForDevChange ( HWND hDlg, PVOID *hNoditfyDevNode )
//
// PARAMETERS:
//
//
// PURPOSE:
//
// RETURN:
///////////////////////////////////////////////////////////////////////////////
void RegisterForDevChange(HWND hDlg, PVOID *hNotifyDevNode)
{
DEV_BROADCAST_DEVICEINTERFACE *pFilterData = (DEV_BROADCAST_DEVICEINTERFACE *)_alloca(sizeof(DEV_BROADCAST_DEVICEINTERFACE));
ASSERT (pFilterData);
ZeroMemory(pFilterData, sizeof(DEV_BROADCAST_DEVICEINTERFACE));
pFilterData->dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
pFilterData->dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
pFilterData->dbcc_classguid = GUID_CLASS_INPUT;
*hNotifyDevNode = RegisterDeviceNotification(hDlg, pFilterData, DEVICE_NOTIFY_WINDOW_HANDLE);
}
///////////////////////////////////////////////////////////////////////////////
// FUNCTION: DecodeAxisPOV ( DWORD dwVal )
//
// PARAMETERS:
//
//
// PURPOSE:
//
// RETURN:
///////////////////////////////////////////////////////////////////////////////
static DWORD DecodeAxisPOV( DWORD dwVal )
{
DWORD dwResult;
if( bPolledPOV ) {
/*
* figure out which direction this value indicates...
*/
if( (dwVal > myPOV[POV_MIN][JOY_POVVAL_FORWARD])
&&(dwVal < myPOV[POV_MAX][JOY_POVVAL_FORWARD]) )
{
dwResult = JOY_POVFORWARD;
}
else if( (dwVal > myPOV[POV_MIN][JOY_POVVAL_BACKWARD])
&&(dwVal < myPOV[POV_MAX][JOY_POVVAL_BACKWARD]) )
{
dwResult = JOY_POVBACKWARD;
}
else if( (dwVal > myPOV[POV_MIN][JOY_POVVAL_LEFT])
&&(dwVal < myPOV[POV_MAX][JOY_POVVAL_LEFT]) )
{
dwResult = JOY_POVLEFT;
}
else if( (dwVal > myPOV[POV_MIN][JOY_POVVAL_RIGHT])
&&(dwVal < myPOV[POV_MAX][JOY_POVVAL_RIGHT]) )
{
dwResult = JOY_POVRIGHT;
}
else
{
dwResult = JOY_POVCENTERED;
}
} else {
dwResult = dwVal;
}
#if 0
{
TCHAR buf[100];
if( bPolledPOV ) {
wsprintf(buf, TEXT("calibrated pov: %d\r\n"), dwResult);
} else {
wsprintf(buf, TEXT("uncalibrated pov: %d\r\n"), dwResult);
}
OutputDebugString(buf);
}
#endif
return dwResult;
}
/*
* doPOVCal - compute calibration for POV for a direction
*/
static void __inline doPOVCal( LPJOYREGHWCONFIG pHWCfg, DWORD dwDir, LPDWORD dwOrder )
{
DWORD dwVal;
int nDir;
for( nDir=0; nDir<JOY_POV_NUMDIRS; nDir++ )
{
if( dwOrder[nDir] == dwDir )
{
break;
}
}
if( nDir == 0 )
{
dwVal = 1;
}
else
{
dwVal = (pHWCfg->hwv.dwPOVValues[dwDir] + pHWCfg->hwv.dwPOVValues[dwOrder[nDir-1]])/2;
}
myPOV[POV_MIN][dwDir] = dwVal;
if( nDir == JOY_POV_NUMDIRS-1 ) {
dwVal = pHWCfg->hwv.dwPOVValues[dwDir]/10l;
dwVal += pHWCfg->hwv.dwPOVValues[dwDir];
} else {
dwVal = (pHWCfg->hwv.dwPOVValues[dwOrder[nDir+1]] + pHWCfg->hwv.dwPOVValues[dwDir])/2;
}
myPOV[POV_MAX][dwDir] = dwVal;
} /* doPOVCal */
///////////////////////////////////////////////////////////////////////////////
// FUNCTION: CalibratePolledPOV( LPJOYREGHWCONFIG pHWCfg )
//
// PARAMETERS:
//
//
// PURPOSE:
//
// RETURN:
///////////////////////////////////////////////////////////////////////////////
void CalibratePolledPOV( LPJOYREGHWCONFIG pHWCfg )
{
DWORD dwOrder[JOY_POV_NUMDIRS];
DWORD dwTmp[JOY_POV_NUMDIRS];
DWORD dwVal;
int nDir,nDir2;
/*
* calibrate POV for polling based ones
*/
for( nDir=0; nDir<JOY_POV_NUMDIRS; nDir++ )
{
dwTmp[nDir] = pHWCfg->hwv.dwPOVValues[nDir];
dwOrder[nDir] = nDir;
}
/*
* sort (did you ever think you'd see a bubble sort again?)
*/
for( nDir=0;nDir<JOY_POV_NUMDIRS;nDir++ )
{
for( nDir2=nDir; nDir2<JOY_POV_NUMDIRS; nDir2++ )
{
if( dwTmp[nDir] > dwTmp[nDir2] )
{
dwVal = dwTmp[nDir];
dwTmp[nDir] = dwTmp[nDir2];
dwTmp[nDir2] = dwVal;
dwVal = dwOrder[nDir];
dwOrder[nDir] = dwOrder[nDir2];
dwOrder[nDir2] = dwVal;
}
}
}
for( nDir=0; nDir<JOY_POV_NUMDIRS; nDir++ )
{
doPOVCal( pHWCfg, nDir, dwOrder );
}
myPOV[POV_MIN][JOY_POV_NUMDIRS] = 0;
myPOV[POV_MAX][JOY_POV_NUMDIRS] = 0;
} /* CalibratePolledPOV */
#endif