//=========================================================================== // CAL.CPP... Would be CALIBRATE.CPP, but that's not 8.3 compliant :( // // Functions: // // CalInitProc // CalXYProc // CalSliderProc // CalPovProc // CalStateChange // CollectCalInfo // EnableXYWindows // GetOEMCtrlString // //=========================================================================== // This is necessary or PSH_WIZARD_LITE will not be defined! #if (_WIN32_IE < 0x0500) #undef _WIN32_IE #define _WIN32_IE 0x0500 #endif // This is necessary for UnregisterDeviceNotification! #if (WINVER < 0x0500) #undef WINVER #define WINVER 0x0500 #endif // Uncomment if we decide to calibrate the POV! #define WE_SUPPORT_CALIBRATING_POVS 1 #include "cplsvr1.h" #include #ifdef _UNICODE #include // For RegisterDeviceNotification stuff! #include // for DBT_ defines!!! #endif // _UNICODE // remove to remove support for calibration of deadzones! //#define DEADZONE 1 #include "resource.h" #include "cal.h" // Data to be shared with other modules #include "calocal.h" // Local Data to this module #include "dicputil.h" // for OnContextMenu and OnHelp #include "pov.h" // for SetDegrees() #include // includes the property sheet functionality #include // for the Str... functions! #include // for pre-defined Registry string names #include "Gradient.h" // for Gradient Fill Slider! // Local function prototypes! static void UpdateXYLabel (const HWND hDlg); static BOOL UpdateProgressLabel (const HWND hDlg); // myitoa prototype is in cplsvr1.h static void reverse (LPTSTR string); static void RawDataSelected (const HWND hWnd, BOOL bEnable); static void WizFinish (const HWND hWnd); // Calibration procedures! INT_PTR CALLBACK CalInitProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); INT_PTR CALLBACK CalXYProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); INT_PTR CALLBACK CalSliderProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); #ifdef WE_SUPPORT_CALIBRATING_POVS INT_PTR CALLBACK CalPovProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); #endif //WE_SUPPORT_CALIBRATING_POVS VOID CALLBACK TimerProc (const HWND hWnd, UINT uMsg, UINT idEvent, DWORD dwTime); //static void EnableSliderWindows (const HWND hWnd, BOOL bEnable); HWND ProgWndCal; // Handle to Progress Control Window //DWORD dwUsage; // Usage flags for the device being calibrated! char nCalState; // Flag state variable! char nPrevCalState; LPMYJOYRANGE pRanges; // Ranges recieved by the Calibration! BOOL bShowRawData; LPWSTR lpwszTypeName; // Set in WM_INIT, Used in GetOEMCtrlString LPDIJOYCONFIG_DX5 pJoyConfig; // DIJC_REGHWCONFIGTYPE information about the device! // extern LPMYJOYRANGE lpCurrentRanges; extern LPDIJOYSTATE lpDIJoyState; // Defined in TEST.CPP extern CDIGameCntrlPropSheet_X *pdiCpl; extern HINSTANCE ghInst; HFONT hTitleFont; static LPDIRECTINPUTDEVICE2 pdiDevice2; static CGradientProgressCtrl *pGradient; static BOOL bGradient; //**************************************************************************** // // FUNCTION: CreateWizard(HWND hwndOwner, LPARAM lParam) // // PURPOSE: Create the Wizard control. // // COMMENTS: // // This function creates the wizard property sheet. //**************************************************************************** short CreateWizard(const HWND hwndOwner, LPARAM lParam) { #ifdef WE_SUPPORT_CALIBRATING_POVS const BYTE nTempArray[] = {IDD_INITIAL, IDD_XY, IDD_SLIDER, IDD_POV }; const DLGPROC pDlgProc[] = {CalInitProc, CalXYProc, CalSliderProc, CalPovProc }; #else const BYTE nTempArray[] = {IDD_INITIAL, IDD_XY, IDD_SLIDER }; const DLGPROC pDlgProc[] = {CalInitProc, CalXYProc, CalSliderProc }; #endif HPROPSHEETPAGE *pPages = new (HPROPSHEETPAGE[sizeof(nTempArray)/sizeof(BYTE)]); if( !pPages ) { return 0; } // Allocate and Zero the Page header memory PROPSHEETHEADER *ppsh = new (PROPSHEETHEADER); if( !ppsh ) { delete[] (pPages); return 0; } ZeroMemory(ppsh, sizeof(PROPSHEETHEADER)); ppsh->dwSize = sizeof(PROPSHEETHEADER); ppsh->dwFlags = PSH_WIZARD_LITE | PSH_NOAPPLYNOW | PSH_USEICONID; ppsh->hwndParent = hwndOwner; ppsh->pszIcon = MAKEINTRESOURCE(IDI_GCICON); ppsh->hInstance = ghInst; ppsh->phpage = pPages; ppsh->pszbmWatermark = MAKEINTRESOURCE(IDB_CALHD); PROPSHEETPAGE *ppsp = new (PROPSHEETPAGE); if( !ppsp ) { delete[] (pPages); delete (ppsh); return 0; } ZeroMemory(ppsp, sizeof(PROPSHEETPAGE)); ppsp->dwSize = sizeof(PROPSHEETPAGE); // ppsp->pszTitle = MAKEINTRESOURCE(nTabID); ppsp->hInstance = ghInst; ppsp->lParam = lParam; while( ppsh->nPages < (sizeof(nTempArray)/sizeof(BYTE)) ) { ppsp->pfnDlgProc = pDlgProc[ppsh->nPages]; ppsp->pszTemplate = MAKEINTRESOURCE(nTempArray[ppsh->nPages]); ppsh->phpage[ppsh->nPages] = CreatePropertySheetPage(ppsp); ppsh->nPages++; } if( ppsp ) delete (ppsp); short nRet = (short)PropertySheet(ppsh); if( pPages ) delete[] (pPages); // Clean up! if( ppsh ) delete (ppsh); return(nRet); } //******************************************************************************* // // FUNCTION: CalInitProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) // // PURPOSE: Procedure for Start-up screen // // COMMENTS: This function is responsible for display of text and bitmap. // Since it is also the only page that is Guarenteed to be hit, // it is also responsible for creating, deleteing, and storing // everything for the calibration wizard. // //******************************************************************************* INT_PTR CALLBACK CalInitProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { static HFONT hBoldFont; static PVOID hNotifyDevNode; switch( uMsg ) { case WM_LBUTTONDOWN: // Click Drag service for PropSheets! PostMessage(GetParent(hWnd), WM_NCLBUTTONDOWN, (WPARAM)HTCAPTION, lParam); break; #ifdef _UNICODE case WM_DEVICECHANGE: if( (UINT)wParam == DBT_DEVICEREMOVECOMPLETE ) ::PostMessage(GetParent(hWnd), WM_COMMAND, IDCANCEL, 0); break; #endif // OnInit case WM_INITDIALOG: // Init to FALSE to turn off Gradient fill! bGradient = FALSE; // According to knowlege base artical Q138505, this is the prescribed method of removing // the context sensitive help '?' from the title bar. { LONG style = ::GetWindowLong(GetParent(hWnd), GWL_EXSTYLE); style &= ~WS_EX_CONTEXTHELP; HWND hParent = GetParent(hWnd); ::SetWindowLong(hParent, GWL_EXSTYLE, style); // Set up the Device Notification #ifdef _UNICODE RegisterForDevChange(hWnd, &hNotifyDevNode); #endif HDC myDC = GetDC(hWnd); if( myDC ) { // Prefix Whistler 45095 hTitleFont = CreateFont(-MulDiv(8, GetDeviceCaps(myDC, LOGPIXELSY), 72), 0, 0, 0, FW_SEMIBOLD, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY, DEFAULT_PITCH | FF_DONTCARE, TEXT("MS Shell Dlg")); // Do the Create font thing... hBoldFont = CreateFont(-MulDiv(15, GetDeviceCaps(myDC, LOGPIXELSY), 72), 0, 0, 0, FW_SEMIBOLD, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY, DEFAULT_PITCH | FF_ROMAN, TEXT("MS Shell Dlg")); ReleaseDC(hWnd, myDC); } if( hBoldFont ) ::SendDlgItemMessage(hWnd, IDC_INIT_TITLE, WM_SETFONT, (WPARAM)hBoldFont, TRUE); CenterDialog(hWnd); ::PostMessage(hParent, PSM_SETWIZBUTTONS, 0, (LPARAM)(DWORD)PSWIZB_NEXT); bShowRawData = FALSE; // Allocate the memory for the ranges! pRanges = new MYJOYRANGE; assert(pRanges); // Set Everything to ZeroMemory(pRanges, sizeof(MYJOYRANGE)); // Get the "best guess" ranges... CopyMemory(pRanges, lpCurrentRanges, sizeof(MYJOYRANGE)); pdiCpl->GetDevice(&pdiDevice2); // Attempt to Set them... die if you can't! SetMyRanges(pdiDevice2, pRanges, pdiCpl->GetStateFlags()->nAxis); if( FAILED(GetLastError()) ) { Error(hWnd, (short)IDS_USER_MODE_TITLE, (short)IDS_USER_MODE); PostMessage(GetParent(hWnd), WM_SYSCOMMAND, SC_CLOSE, 0L); } pJoyConfig = new(DIJOYCONFIG_DX5); assert (pJoyConfig); pJoyConfig->dwSize = sizeof (DIJOYCONFIG_DX5); LPDIRECTINPUTJOYCONFIG pdiJoyConfig; pdiCpl->GetJoyConfig(&pdiJoyConfig); HRESULT hres; // Retrieve and store Hardware Configuration about the device! hres = pdiJoyConfig->GetConfig(pdiCpl->GetID(), (LPDIJOYCONFIG)pJoyConfig, DIJC_REGHWCONFIGTYPE | DIJC_GUIDINSTANCE); if( SUCCEEDED(hres) ) { bPolledPOV = (pJoyConfig->hwc.hws.dwFlags & JOY_HWS_HASPOV) && (pJoyConfig->hwc.hws.dwFlags & JOY_HWS_POVISPOLL); CalibratePolledPOV( &pJoyConfig->hwc ); } } break; // Change the background of all Static text fields to WHITE case WM_CTLCOLORSTATIC: return(LRESULT)GetStockObject(WHITE_BRUSH); case WM_DESTROY: if( pJoyConfig ) delete (pJoyConfig); if( lpwszTypeName ) LocalFree(lpwszTypeName); pdiDevice2->Unacquire(); SetCalibrationMode( FALSE ); if( hTitleFont ) DeleteObject((HGDIOBJ)hTitleFont); if( hBoldFont ) DeleteObject((HGDIOBJ)hBoldFont); // if you call this function you will hang up the system for 30 seconds or more!!! #ifdef _UNICODE if( hNotifyDevNode ) UnregisterDeviceNotification(hNotifyDevNode); #endif // _UNICODE break; } return(DefWindowProc(hWnd, uMsg, wParam, lParam)); } //******************************************************************************* // // FUNCTION: CalXYProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) // // PURPOSE: Procedure for first three stages of calibration // // COMMENTS: This function is responsible for capture of X/Y and Center values! // //******************************************************************************* INT_PTR CALLBACK CalXYProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch( uMsg ) { case WM_LBUTTONDOWN: // Click Drag service for PropSheets! PostMessage(GetParent(hWnd), WM_NCLBUTTONDOWN, (WPARAM)HTCAPTION, lParam); break; // OnInit case WM_INITDIALOG: { // set up the local globals nCalState = JCS_XY_CENTER1; nPrevCalState = JCS_INIT; // Get the JoyConfig Interface Pointer! LPDIRECTINPUTJOYCONFIG pdiJoyConfig; pdiCpl->GetJoyConfig(&pdiJoyConfig); if( SUCCEEDED(pdiJoyConfig->SetCooperativeLevel(hWnd, DISCL_EXCLUSIVE | DISCL_BACKGROUND)) ) { // Set the font for the ::SendDlgItemMessage(hWnd, IDC_WIZARD_MSG_HDR, WM_SETFONT, (WPARAM)hTitleFont, TRUE); lpwszTypeName = StrDupW(pJoyConfig->wszType); // This sets up the Windows and the global ProgWndCal! UpdateXYLabel(hWnd); // Set up for first round CalStateChange( hWnd, (BYTE)pJoyConfig->hwc.hws.dwFlags ); VERIFY(SUCCEEDED(SetCalibrationMode(TRUE))); VERIFY(FAILED(pdiDevice2->Acquire())); } } break; // Change the background of all Static text fields to WHITE case WM_CTLCOLORSTATIC: // We only want to paint the background for the items in the top white rectangle! switch( GetDlgCtrlID((HWND)lParam) ) { case IDC_WIZARD_MSG: case IDC_HEADERFRAME: case IDC_WIZARD_MSG_HDR: return(LRESULT)GetStockObject(WHITE_BRUSH); } return(FALSE); // OnNotify case WM_NOTIFY: switch( ((NMHDR FAR *) lParam)->code ) { case PSN_KILLACTIVE: KillTimer(hWnd, ID_CAL_TIMER); break; case PSN_RESET: // reset to the original values KillTimer(hWnd, ID_CAL_TIMER); break; case PSN_SETACTIVE: SetTimer( hWnd, ID_CAL_TIMER, CALIBRATION_INTERVAL, (TIMERPROC)TimerProc); // Sorry, you can't go back to the first page... if( nCalState > JCS_XY_CENTER1 ) ::PostMessage(GetParent(hWnd), PSM_SETWIZBUTTONS, 0, (LPARAM)(DWORD)PSWIZB_NEXT | PSWIZB_BACK); else ::PostMessage(GetParent(hWnd), PSM_SETWIZBUTTONS, 0, (LPARAM)(DWORD)PSWIZB_NEXT); break; case PSN_WIZBACK: // Determine what the next calibration stage is! // Look out... we're backing up! if( nCalState == nPrevCalState ) nPrevCalState--; nCalState = nPrevCalState; CalStateChange(hWnd, (BYTE)pJoyConfig->hwc.hws.dwFlags); // No more backing up! if( nCalState == JCS_XY_CENTER1 ) ::PostMessage(GetParent(hWnd), PSM_SETWIZBUTTONS, 0, (LPARAM)(DWORD)PSWIZB_NEXT); SetWindowLongPtr(hWnd, DWLP_MSGRESULT, (nCalState < JCS_XY_CENTER1) ? IDD_INITIAL : -1); return(nCalState < JCS_XY_CENTER1) ? IDD_INITIAL : -1; case PSN_WIZNEXT: nPrevCalState = nCalState; ::PostMessage(GetParent(hWnd), PSM_SETWIZBUTTONS, 0, (LPARAM)(DWORD)PSWIZB_NEXT | PSWIZB_BACK); #if 0 // Determine what the next calibration stage is! #ifndef DEADZONE //while ((!(pdiCpl->GetStateFlags()->nAxis & 1<GetStateFlags()->nAxis & (1< JCS_FINI ) ::PostMessage(GetParent(hWnd), PSM_SETWIZBUTTONS, 0, (LPARAM)(DWORD)PSWIZB_FINISH | PSWIZB_BACK); else if( nCalState < JCS_Z_MOVE ) CalStateChange( hWnd, (BYTE)pJoyConfig->hwc.hws.dwFlags ); SetWindowLongPtr(hWnd, DWLP_MSGRESULT, (nCalState < JCS_Z_MOVE) ? -1 : IDD_SLIDER ); return(nCalState < JCS_Z_MOVE) ? -1 : IDD_SLIDER; default: return(FALSE); } break; // OnCommand case WM_COMMAND: switch( LOWORD(wParam) ) { case IDC_RAWDATA: RawDataSelected(hWnd, bShowRawData = !bShowRawData); break; } break; // OnDestroy case WM_DESTROY: if( pRanges ) { delete (pRanges); pRanges = NULL; } break; default: return(FALSE); } return(TRUE); } //**************************************************************************** // // FUNCTION: CalSliderProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) // // PURPOSE: Procedure // // COMMENTS: // // This function creates the wizard property sheet. //**************************************************************************** INT_PTR CALLBACK CalSliderProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch( uMsg ) { case WM_LBUTTONDOWN: // Click Drag service for PropSheets! PostMessage(GetParent(hWnd), WM_NCLBUTTONDOWN, (WPARAM)HTCAPTION, lParam); break; case WM_INITDIALOG: // Set the Control font! ::SendDlgItemMessage(hWnd,IDC_WIZARD_MSG_HDR, WM_SETFONT, (WPARAM)hTitleFont, TRUE); #ifdef DEADZONE ::SendDlgItemMessage(hWnd, IDC_DEADZONE_TITLE, WM_SETFONT, (WPARAM)hTitleFont, TRUE); ::SendDlgItemMessage(hWnd, IDC_SATURATION_TITLE, WM_SETFONT, (WPARAM)hTitleFont, TRUE); #endif //DEADZONE // Setup the Progress bar! ProgWndCal = GetDlgItem(hWnd, IDC_SLIDER); // do the Gradient fill maddness! { HDC hDC = ::GetWindowDC(hWnd); if( hDC ) { bGradient = (BOOL)(GetDeviceCaps(hDC, NUMCOLORS) < 0); if( bGradient ) { pGradient = new (CGradientProgressCtrl); pGradient->SubclassWindow(GetDlgItem(hWnd, IDC_SLIDER)); pGradient->SetDirection(HORIZONTAL); //pGradient->ShowPercent(); pGradient->SetStartColor(COLORREF(RGB(0,0,255))); pGradient->SetEndColor(COLORREF(RGB(0,0,0))); pGradient->SetBkColor(COLORREF(RGB(180,180,180))); } ::ReleaseDC(hWnd, hDC); } } if( nCalState < JCS_FINI ) { // UpdateProgressLabel MUST be called Before CalStateChange!!! UpdateProgressLabel(hWnd); // If we're not using the gradient control, set the bar // colour PBM_SETBARCOLOR is WM_USER+9... YES, it's undocumented... if( !bGradient ) { ::PostMessage(ProgWndCal, WM_USER+9, 0, (LPARAM)ACTIVE_COLOR); } } else { ::PostMessage(GetParent(hWnd), PSM_PRESSBUTTON, (WPARAM)(int)PSBTN_NEXT, 0); } break; case WM_DESTROY: if( bGradient ) if( pGradient ) delete (pGradient); break; // OnCommand case WM_COMMAND: switch( LOWORD(wParam) ) { case IDC_RAWDATA: RawDataSelected(hWnd, bShowRawData = !bShowRawData); if( bGradient ) pGradient->ShowPercent(bShowRawData); break; } break; // Change the background of all Static text fields to WHITE case WM_CTLCOLORSTATIC: // We only want to paint the background for the items in the top white rectangle! switch( GetDlgCtrlID((HWND)lParam) ) { case IDC_WIZARD_MSG: case IDC_HEADERFRAME: case IDC_WIZARD_MSG_HDR: return(LRESULT)GetStockObject(WHITE_BRUSH); } return(FALSE); case WM_NOTIFY: switch( ((NMHDR FAR *) lParam)->code ) { case PSN_KILLACTIVE: KillTimer(hWnd, ID_CAL_TIMER); break; case PSN_SETACTIVE: // Set up for first round CalStateChange( hWnd, (BYTE)NULL ); SetTimer( hWnd, ID_CAL_TIMER, CALIBRATION_INTERVAL, (TIMERPROC)TimerProc); ::PostMessage(GetParent(hWnd), PSM_SETWIZBUTTONS, 0, (LPARAM)(DWORD)PSWIZB_NEXT | PSWIZB_BACK); break; case PSN_WIZBACK: // Determine what the previous calibration stage is! if( nCalState == nPrevCalState ) { DWORD dwAxis = pdiCpl->GetStateFlags()->nAxis; nPrevCalState --; while( ( !(dwAxis & (1<<(--nPrevCalState)) ) ) && (nPrevCalState > JCS_XY_CENTER2) ){ ; } nPrevCalState ++; } nCalState = nPrevCalState; if( nCalState > JCS_XY_CENTER2 ) { // UpdateProgressLabel MUST be called Before CalStateChange!!! UpdateProgressLabel(hWnd); CalStateChange( hWnd, (BYTE)NULL ); } SetWindowLongPtr(hWnd, DWLP_MSGRESULT, (nCalState < JCS_Z_MOVE) ? IDD_XY : -1); return(nCalState < JCS_Z_MOVE) ? IDD_XY : -1; case PSN_WIZNEXT: nPrevCalState = nCalState; // Determine what the next calibration stage is! while( (!(pdiCpl->GetStateFlags()->nAxis & 1<rgdwPOV, hWnd); break; case WM_INITDIALOG: { // Set the POV position to the Up position and Set the Text! nCalState = JCS_POV_MOVEUP; HWND hwndPOV = GetDlgItem(hWnd, IDC_JOYPOV); // Disable RTL flag SetWindowLongPtr(hwndPOV, GWL_EXSTYLE, GetWindowLongPtr(hwndPOV,GWL_EXSTYLE)&~WS_EX_LAYOUTRTL); // Set the Control font! ::SendDlgItemMessage(hWnd,IDC_WIZARD_MSG_HDR, WM_SETFONT, (WPARAM)hTitleFont, TRUE); break; } case WM_DESTROY: break; case WM_COMMAND: switch( LOWORD(wParam) ) { case IDC_RAWDATA: RawDataSelected(hWnd, bShowRawData = !bShowRawData); break; case IDC_SETPOV: //if( joyGetPosEx(pdiCpl->GetID(), lpJoyInfo) == JOYERR_NOERROR ) { if( SUCCEEDED(DIUtilPollJoystick(pdiDevice2, lpDIJoyState)) ) { CollectCalInfo(hWnd, lpDIJoyState); // Insert the POV information! switch( nCalState ) { case JCS_POV_MOVEUP: // Store what we got! pRanges->dwPOV[JOY_POVVAL_FORWARD] = pJoyConfig->hwc.hwv.dwPOVValues[JOY_POVVAL_FORWARD] = (pJoyConfig->hwc.hws.dwFlags & JOY_HWS_POVISPOLL) ? lpDIJoyState->rgdwPOV[0] : 0; // Once you're here... disable the buttons... no going back and forth... ::SendMessage(GetParent(hWnd), PSM_SETWIZBUTTONS, 0, (LPARAM)(DWORD)PSWIZB_DISABLEDFINISH); break; case JCS_POV_MOVERIGHT: // Store what we got! pRanges->dwPOV[JOY_POVVAL_RIGHT] = pJoyConfig->hwc.hwv.dwPOVValues[JOY_POVVAL_RIGHT] = (pJoyConfig->hwc.hws.dwFlags & JOY_HWS_POVISPOLL) ? lpDIJoyState->rgdwPOV[0] : 0; break; case JCS_POV_MOVEDOWN: // Store what we got! pRanges->dwPOV[JOY_POVVAL_BACKWARD] = pJoyConfig->hwc.hwv.dwPOVValues[JOY_POVVAL_BACKWARD] = (pJoyConfig->hwc.hws.dwFlags & JOY_HWS_POVISPOLL) ? lpDIJoyState->rgdwPOV[0] : 0; break; case JCS_POV_MOVELEFT: // Store what we got! pRanges->dwPOV[JOY_POVVAL_LEFT] = pJoyConfig->hwc.hwv.dwPOVValues[JOY_POVVAL_LEFT] = (pJoyConfig->hwc.hws.dwFlags & JOY_HWS_POVISPOLL) ? lpDIJoyState->rgdwPOV[0] : 0; ::PostMessage(GetParent(hWnd), PSM_SETWIZBUTTONS, 0, (LPARAM)(DWORD)PSWIZB_FINISH); // Take away the controls... it's all over! DestroyWindow(GetDlgItem(hWnd, IDC_JOYPOV)); DestroyWindow(GetDlgItem(hWnd, IDC_SETPOV)); break; } } nCalState++; CalStateChange(hWnd, NULL); // Set the focus back to IDC_SETPOV button! SendMessage(hWnd, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hWnd, IDC_SETPOV), (LPARAM)TRUE); break; } break; // Change the background of all Static text fields to WHITE case WM_CTLCOLORSTATIC: // We only want to paint the background for the items in the top white rectangle! switch( GetDlgCtrlID((HWND)lParam) ) { case IDC_WIZARD_MSG: case IDC_HEADERFRAME: case IDC_WIZARD_MSG_HDR: return(LRESULT)GetStockObject(WHITE_BRUSH); } return(FALSE); case WM_NOTIFY: switch( ((NMHDR FAR *) lParam)->code ) { case PSN_KILLACTIVE: KillTimer(hWnd, ID_CAL_TIMER); return(TRUE); case PSN_RESET: break; case PSN_SETACTIVE: if( nCalState == JCS_POV_MOVEUP ) { DoTestPOV(FORCE_POV_REFRESH, lpDIJoyState->rgdwPOV, hWnd); } CalStateChange(hWnd, NULL); break; case PSN_WIZFINISH: WizFinish(hWnd); break; case PSN_WIZBACK: // Determine what the next calibration stage is! if( nCalState == nPrevCalState ) { DWORD dwAxis = pdiCpl->GetStateFlags()->nAxis; nPrevCalState --; while( ( !(dwAxis & (1<<(--nPrevCalState)) ) ) && (nPrevCalState > JCS_XY_CENTER2) ){ ; } nPrevCalState ++; } nCalState = nPrevCalState; if( nCalState > JCS_XY_CENTER2 ) { if( nCalState <= JCS_S1_MOVE ) { UpdateProgressLabel(hWnd); CalStateChange( hWnd, (BYTE)NULL ); } else if( bPolledPOV ) { SetWindowLongPtr(hWnd, DWLP_MSGRESULT, IDD_POV ); return(IDD_POV); } } else { SetWindowLongPtr(hWnd, DWLP_MSGRESULT, (nCalState < JCS_Z_MOVE) ? IDD_XY : -1); return(nCalState < JCS_Z_MOVE) ? IDD_XY : -1; } break; case PSN_WIZNEXT: // Take away the controls... it's all over! DestroyWindow(GetDlgItem(hWnd, IDC_JOYPOV)); DestroyWindow(GetDlgItem(hWnd, IDC_SETPOV)); // Go on to Finish! nCalState = JCS_FINI; CalStateChange(hWnd, NULL); // Get rid of Back and bring on Finish! ::PostMessage(GetParent(hWnd), PSM_SETWIZBUTTONS, 0, (LPARAM)(DWORD)PSWIZB_FINISH); break; default: return(FALSE); } break; default: return(FALSE); } return(TRUE); } #endif // WE_SUPPORT_CALIBRATING_POVS //******************************************************************************* // // FUNCTION: CalStateChange( HWND hDlg, BYTE nDeviceFlags ) // // PURPOSE: Procedure to set up the dialog for its' Next stage // // COMMENTS: // //******************************************************************************* void CalStateChange( HWND hDlg, BYTE nDeviceFlags ) { short nMsgID = IDS_JOYCAL_MOVE; short nTitleID = IDS_AXIS_CALIBRATION; #define MAX_CAL_VAL 0xfffffff switch( nCalState ) { case JCS_XY_CENTER1: case JCS_XY_CENTER2: // Set up the string ID if( nDeviceFlags & JOY_HWS_ISYOKE ) nMsgID = IDS_JOYCALXY_CENTERYOKE; else if( nDeviceFlags & JOY_HWS_ISCARCTRL ) nMsgID = IDS_JOYCALXY_CENTERCAR; else if( nDeviceFlags & JOY_HWS_ISGAMEPAD ) nMsgID = IDS_JOYCALXY_CENTERGAMEPAD; else nMsgID = IDS_JOYCALXY_CENTER; // Setup the Header TextID nTitleID = (nCalState == JCS_XY_CENTER1) ? IDS_CENTER_HDR : IDS_VERIFY_CENTER_HDR; EnableXYWindows( hDlg ); break; case JCS_XY_MOVE: // Set up the string ID if( nDeviceFlags & JOY_HWS_ISYOKE ) nMsgID = IDS_JOYCALXY_MOVEYOKE; else if( nDeviceFlags & JOY_HWS_ISCARCTRL ) nMsgID = IDS_JOYCALXY_MOVECAR; else if( nDeviceFlags & JOY_HWS_ISGAMEPAD ) nMsgID = IDS_JOYCALXY_MOVEGAMEPAD; else nMsgID = IDS_JOYCALXY_MOVE; // Blast the data so we are sure to get the correct data! pRanges->jpMin.dwX = MAX_CAL_VAL; pRanges->jpMax.dwX = -MAX_CAL_VAL; pRanges->jpMin.dwY = MAX_CAL_VAL; pRanges->jpMax.dwY = -MAX_CAL_VAL; EnableXYWindows( hDlg ); break; /* case JCS_XY_CENTER1: // Set up the string ID if ( nDeviceFlags & JOY_HWS_ISYOKE ) nMsgID = IDS_JOYCALXY_CENTERYOKE; else if( nDeviceFlags & JOY_HWS_ISCARCTRL ) nMsgID = IDS_JOYCALXY_CENTERCAR; else if( nDeviceFlags & JOY_HWS_ISGAMEPAD ) nMsgID = IDS_JOYCALXY_CENTERGAMEPAD; else nMsgID = IDS_JOYCALXY_CENTER; // Setup the Header TextID nTitleID = IDS_CENTER_HDR; EnableXYWindows( hDlg ); break; case JCS_XY_MOVE: // Set up the string ID if( nDeviceFlags & JOY_HWS_ISYOKE ) nMsgID = IDS_JOYCALXY_MOVEYOKE; else if( nDeviceFlags & JOY_HWS_ISCARCTRL ) nMsgID = IDS_JOYCALXY_MOVECAR; else if( nDeviceFlags & JOY_HWS_ISGAMEPAD ) nMsgID = IDS_JOYCALXY_MOVEGAMEPAD; else nMsgID = IDS_JOYCALXY_MOVE; // Blast the data so we are sure to get the correct data! pRanges->jpMin.dwX = MAX_CAL_VAL; pRanges->jpMax.dwX = -MAX_CAL_VAL; pRanges->jpMin.dwY = MAX_CAL_VAL; pRanges->jpMax.dwY = -MAX_CAL_VAL; EnableXYWindows( hDlg ); break; case JCS_XY_CENTER2: // Set up the string ID if( nDeviceFlags & JOY_HWS_ISYOKE ) nMsgID = IDS_JOYCALXY_CENTERYOKE; else if( nDeviceFlags & JOY_HWS_ISCARCTRL ) nMsgID = IDS_JOYCALXY_CENTERCAR; else if( nDeviceFlags & JOY_HWS_ISGAMEPAD ) nMsgID = IDS_JOYCALXY_CENTERGAMEPAD; else nMsgID = IDS_JOYCALXY_CENTER; // Setup the Header TextID nTitleID = IDS_VERIFY_CENTER_HDR; EnableXYWindows( hDlg ); break; */ #ifdef DEADZONE case JCS_DEADZONE: // Set up the message string. if( nDeviceFlags & JOY_HWS_ISYOKE ) nMsgID = IDS_YOKE_DEADZONE; else if( nDeviceFlags & JOY_HWS_ISCARCTRL ) nMsgID = IDS_CAR_DEADZONE; else if( nDeviceFlags & JOY_HWS_ISGAMEPAD ) nMsgID = IDS_GAMEPAD_DEADZONE; else nMsgID = IDS_JOYSTICK_DEADZONE; // Set up the title string! nTitleID = IDS_DEADZONE_TITLE; // Setup the controls! EnableXYWindows( hDlg ); // Text Labels are sent in during UpdateXYLabel! // Text fonts are set on INIT! // Setup the Spin positions! { DIPROPDWORD DIPropDW; ZeroMemory(DIPropDW, sizeof(DIPROPDWORD)); DIPropDW.diph.dwSize = sizeof(DIPROPDWORD); DIPropDW.diph.dwHeaderSize = sizeof(DIPROPHEADER); DIPropDW.diph.dwObj = DIJOFS_X; DIPropDW.diph.dwHow = DIPH_BYOFFSET; HWND hSpinCtrl; // Deadzone first... if( SUCCEEDED(pdiDevice2->GetProperty(DIPROP_DEADZONE, &DIPropDW.diph)) ) { // First the Deadzone... hSpinCtrl = GetDlgItem(hDlg, IDC_X_DEADZONE_SPIN); ::PostMessage(hSpinCtrl, UDM_SETRANGE, 0, MAKELPARAM(1000, 1)); ::PostMessage(hSpinCtrl, UDM_SETBASE, 10, 0L); ::PostMessage(hSpinCtrl, UDM_SETPOS, 0, MAKELPARAM(DIPropDW.dwData, 0)); } // Setup the DIPROPDWORD struct! DIPropDW.diph.dwObj = DIJOFS_Y; if( SUCCEEDED(pdiDevice2->GetProperty(DIPROP_DEADZONE, &DIPropDW.diph)) ) { // First the Deadzone... hSpinCtrl = GetDlgItem(hDlg, IDC_Y_DEADZONE_SPIN); ::PostMessage(hSpinCtrl, UDM_SETRANGE, 0, MAKELPARAM(1000, 1)); ::PostMessage(hSpinCtrl, UDM_SETBASE, 10, 0L); ::PostMessage(hSpinCtrl, UDM_SETPOS, 0, MAKELPARAM(DIPropDW.dwData, 0)); } // Now, the Saturation! if( SUCCEEDED(pdiDevice2->GetProperty(DIPROP_SATURATION, &DIPropDW.diph)) ) { hSpinCtrl = GetDlgItem(hDlg, IDC_Y_SATURATION_SPIN); ::PostMessage(hSpinCtrl, UDM_SETRANGE, 0, MAKELPARAM(1000, 1)); ::PostMessage(hSpinCtrl, UDM_SETBASE, 10, 0L); ::PostMessage(hSpinCtrl, UDM_SETPOS, 0, MAKELPARAM(DIPropDW.dwData, 0)); } // Setup the DIPROPDWORD struct! DIPropDW.diph.dwObj = DIJOFS_X; if( SUCCEEDED(pdiDevice2->GetProperty(DIPROP_SATURATION, &DIPropDW.diph)) ) { hSpinCtrl = GetDlgItem(hDlg, IDC_X_SATURATION_SPIN); ::PostMessage(hSpinCtrl, UDM_SETRANGE, 0, MAKELPARAM(1000, 1)); ::PostMessage(hSpinCtrl, UDM_SETBASE, 10, 0L); ::PostMessage(hSpinCtrl, UDM_SETPOS, 0, MAKELPARAM(DIPropDW.dwData, 0)); } } // Draw the rectangle! break; #endif //DEADZONE case JCS_Z_MOVE: { static long nMin = pRanges->jpMin.dwZ; static long nMax = pRanges->jpMax.dwZ; // Set the Range if( bGradient ) pGradient->SetRange(nMin, nMax); ::PostMessage(ProgWndCal, PBM_SETRANGE32, (WPARAM)nMin, (LPARAM)nMax); // Blast the data so we are sure to get the correct data! pRanges->jpMin.dwZ = MAX_CAL_VAL; pRanges->jpMax.dwZ = -MAX_CAL_VAL; } break; case JCS_R_MOVE: { static long nMin = pRanges->jpMin.dwRx; static long nMax = pRanges->jpMax.dwRx; // Set the Range if( bGradient ) pGradient->SetRange(nMin, nMax); ::PostMessage(ProgWndCal, PBM_SETRANGE32, (WPARAM)nMin, (LPARAM)nMax); // Blast the data so we are sure to get the correct data! pRanges->jpMin.dwRx = MAX_CAL_VAL; pRanges->jpMax.dwRx = -MAX_CAL_VAL; } break; case JCS_U_MOVE: { static long nMin = pRanges->jpMin.dwRy; static long nMax = pRanges->jpMax.dwRy; // Set the Range if( bGradient ) pGradient->SetRange(nMin, nMax); ::PostMessage(ProgWndCal, PBM_SETRANGE32, (WPARAM)nMin, (LPARAM)nMax); // Blast the data so we are sure to get the correct data! pRanges->jpMin.dwRy = MAX_CAL_VAL; pRanges->jpMax.dwRy = -MAX_CAL_VAL; } break; case JCS_V_MOVE: { static long nMin = pRanges->jpMin.dwRz; static long nMax = pRanges->jpMax.dwRz; // Set the Range if( bGradient ) pGradient->SetRange(nMin, nMax); ::PostMessage(ProgWndCal, PBM_SETRANGE32, (WPARAM)nMin, (LPARAM)nMax); // Blast the data so we are sure to get the correct data! pRanges->jpMin.dwRz = MAX_CAL_VAL; pRanges->jpMax.dwRz = -MAX_CAL_VAL; } break; case JCS_S0_MOVE: { static long nMin = pRanges->jpMin.dwS0; static long nMax = pRanges->jpMax.dwS0; // Set the Range if( bGradient ) pGradient->SetRange(nMin, nMax); ::PostMessage(ProgWndCal, PBM_SETRANGE32, (WPARAM)nMin, (LPARAM)nMax); // Blast the data so we are sure to get the correct data! pRanges->jpMin.dwS0 = MAX_CAL_VAL; pRanges->jpMax.dwS0 = -MAX_CAL_VAL; } break; case JCS_S1_MOVE: { static long nMin = pRanges->jpMin.dwS1; static long nMax = pRanges->jpMax.dwS1; // Set the Range if( bGradient ) pGradient->SetRange(nMin, nMax); ::PostMessage(ProgWndCal, PBM_SETRANGE32, (WPARAM)nMin, (LPARAM)nMax); // Blast the data so we are sure to get the correct data! pRanges->jpMin.dwS1 = MAX_CAL_VAL; pRanges->jpMax.dwS1 = -MAX_CAL_VAL; } break; #ifdef WE_SUPPORT_CALIBRATING_POVS case JCS_POV_MOVEUP: lpDIJoyState->rgdwPOV[0] = JOY_POVFORWARD; DoTestPOV(HAS_POV1 | HAS_CALIBRATED, lpDIJoyState->rgdwPOV, hDlg); nMsgID = IDS_JOYCALPOV_MOVE; nTitleID = IDS_POV_CALIBRATION; break; case JCS_POV_MOVERIGHT: lpDIJoyState->rgdwPOV[0] = JOY_POVRIGHT; DoTestPOV(HAS_POV1 | HAS_CALIBRATED, lpDIJoyState->rgdwPOV, hDlg); nMsgID = IDS_JOYCALPOV_MOVE; nTitleID = IDS_POV_CALIBRATION; break; case JCS_POV_MOVEDOWN: lpDIJoyState->rgdwPOV[0] = JOY_POVBACKWARD; DoTestPOV(HAS_POV1 | HAS_CALIBRATED, lpDIJoyState->rgdwPOV, hDlg); nMsgID = IDS_JOYCALPOV_MOVE; nTitleID = IDS_POV_CALIBRATION; break; case JCS_POV_MOVELEFT: lpDIJoyState->rgdwPOV[0] = JOY_POVLEFT; DoTestPOV(HAS_POV1 | HAS_CALIBRATED, lpDIJoyState->rgdwPOV, hDlg); nMsgID = IDS_JOYCALPOV_MOVE; nTitleID = IDS_POV_CALIBRATION; break; #endif //WE_SUPPORT_CALIBRATING_POVS case JCS_FINI: nMsgID = IDS_JOYCAL_DONE; nTitleID = IDS_CALIBRATION_FINI; break; default: #ifdef _DEBUG OutputDebugString(TEXT("GCDEF.DLL: CAL.CPP: CalStateChange: nCalState doesn't match any known Calibration States!\n")); #endif return; } // END OF SWITCH // load and set the text TCHAR lptszMsg[MAX_STR_LEN]; DWORD nStrLen =sizeof(lptszMsg) - 1; // see if there is any OEM text specified if( pJoyConfig->hwc.dwUsageSettings & JOY_US_ISOEM ) { GetOEMCtrlString(lptszMsg, &nStrLen); } else { nStrLen = 0; } // nStrLen will be non-zero if GetOEMCtrlString is successfull! if( nStrLen == 0 ) { VERIFY(LoadString(ghInst, nMsgID, lptszMsg, MAX_STR_LEN)); switch( nMsgID ) { case IDS_JOYCAL_MOVE: { TCHAR lptszBuff[STR_LEN_32]; LPTSTR lpDup = StrDup(lptszMsg); if( lpDup ) { ::SendDlgItemMessage(hDlg, IDC_JOYLIST2_LABEL, WM_GETTEXT, (WPARAM)STR_LEN_32, (LPARAM)lptszBuff); if( lstrlen(lpDup) + lstrlen(lptszBuff) < MAX_STR_LEN ) { wsprintf(lptszMsg, lpDup, lptszBuff); } else { #ifdef _DEBUG OutputDebugString(TEXT("Cal.cpp: can't make correct joycalmove label.\n")); #endif } LocalFree(lpDup); } } break; } } // Send the smaller message ::SendDlgItemMessage(hDlg, IDC_WIZARD_MSG, WM_SETTEXT, 0, (LPARAM)(LPCTSTR)lptszMsg); VERIFY(LoadString(ghInst, nTitleID, lptszMsg, MAX_STR_LEN)); // Send the Bold Header message ::SendDlgItemMessage(hDlg, IDC_WIZARD_MSG_HDR, WM_SETTEXT, 0, (LPARAM)(LPCTSTR)lptszMsg); // Take care of the RawData dialog items! switch( nCalState ) { // Don't do the raw data thing if you don't have the checkbox! case JCS_XY_CENTER1: case JCS_XY_CENTER2: case JCS_FINI: break; // Do the percent for the pages that need it! case JCS_Z_MOVE: case JCS_R_MOVE: case JCS_U_MOVE: case JCS_V_MOVE: case JCS_S0_MOVE: case JCS_S1_MOVE: if( bGradient ) { if( pGradient ) { pGradient->ShowPercent(bShowRawData); } } // Missing break intentional!!! default: RawDataSelected(hDlg, bShowRawData); ::SendDlgItemMessage(hDlg, IDC_RAWDATA, BM_SETCHECK, (bShowRawData) ? BST_CHECKED : BST_UNCHECKED, 0); break; } } // *** end of CalStateChange //******************************************************************************* // // FUNCTION: CollectCalInfo( HWND hDlg, LPDIJOYSTATE pdiJoyState ) // // PURPOSE: Procedure to Collect Calibration Data // // COMMENTS: // //******************************************************************************* BOOL CollectCalInfo( HWND hDlg, LPDIJOYSTATE pdiJoyState ) { TCHAR tsz[32]; //So the largest number can be 10^31 (>> 2^64). switch( nCalState ) { // remember XY center case JCS_XY_CENTER1: // store the initial centres! pRanges->jpCenter.dwY = pdiJoyState->lY; pRanges->jpCenter.dwX = pdiJoyState->lX; // We Have an X/Y, so let's check for our Pens! CreatePens(); break; // remember max/min XY values case JCS_XY_MOVE: if( pdiJoyState->lX > pRanges->jpMax.dwX ) pRanges->jpMax.dwX = pdiJoyState->lX; else if( pdiJoyState->lX < pRanges->jpMin.dwX ) pRanges->jpMin.dwX = pdiJoyState->lX; if( pdiJoyState->lY > pRanges->jpMax.dwY ) pRanges->jpMax.dwY = pdiJoyState->lY; else if( pdiJoyState->lY < pRanges->jpMin.dwY ) pRanges->jpMin.dwY = pdiJoyState->lY; // if IDC_RAWXOUTPUT is visible, then so is IDC_RAWYOUTPUT... // no bother to even ask. if( bShowRawData ) { static POINT ptOld = {DELTA,DELTA}; if( (ptOld.x != pdiJoyState->lX) || (ptOld.y != pdiJoyState->lY) ) { myitoa(pdiJoyState->lX, &tsz[0]); ::SendDlgItemMessage(hDlg, IDC_RAWXOUTPUT, WM_SETTEXT, 0, (LPARAM)(LPCTSTR)tsz); myitoa(pdiJoyState->lY, &tsz[0]); ::SendDlgItemMessage(hDlg, IDC_RAWYOUTPUT, WM_SETTEXT, 0, (LPARAM)(LPCTSTR)tsz); ptOld.x = pdiJoyState->lX; ptOld.y = pdiJoyState->lY; } } // Scale before send it to DoJoyMove! { RECT rc; GetClientRect(GetDlgItem(hDlg, IDC_JOYLIST1), &rc); // Casting to the UINT will change the sign! UINT nRange = (UINT)(pRanges->jpMax.dwX - pRanges->jpMin.dwX); float nScaledRange = (float)(rc.right-DELTA); if( nRange ) nScaledRange /= (float)nRange; // Scale X pdiJoyState->lX = (long)((pdiJoyState->lX - pRanges->jpMin.dwX) * nScaledRange); // Scale Y if( nRange ) nScaledRange = (float)rc.bottom / (float)nRange; pdiJoyState->lY = (long)((pdiJoyState->lY - pRanges->jpMin.dwY) * nScaledRange); } DoJoyMove( hDlg, (BYTE)HAS_X|HAS_Y ); break; case JCS_XY_CENTER2: // Average the Y pRanges->jpCenter.dwY = (pRanges->jpCenter.dwY += pdiJoyState->lY)>>1; //Average the X pRanges->jpCenter.dwX = (pRanges->jpCenter.dwX += pdiJoyState->lX)>>1; break; // remember max/min Z value case JCS_Z_MOVE: // Set new Min's and Max's... // Set a new Center whenever either is hit! if( pdiJoyState->lZ > pRanges->jpMax.dwZ ) { pRanges->jpMax.dwZ = pdiJoyState->lZ; pRanges->jpCenter.dwZ = (pRanges->jpMax.dwZ+pRanges->jpMin.dwZ)>>1; } else if( pdiJoyState->lZ < pRanges->jpMin.dwZ ) { pRanges->jpMin.dwZ = pdiJoyState->lZ; pRanges->jpCenter.dwZ = (pRanges->jpMax.dwZ+pRanges->jpMin.dwZ)>>1; } // Do the position status // Update the text if( bShowRawData ) { myitoa(pdiJoyState->lZ, &tsz[0]); ::SendDlgItemMessage(hDlg, IDC_RAWXOUTPUT, WM_SETTEXT, 0, (LPARAM)(LPCTSTR)tsz); } if( bGradient ) pGradient->SetPos(pdiJoyState->lZ); ::PostMessage(ProgWndCal, PBM_SETPOS, (WPARAM)pdiJoyState->lZ, 0L); break; // remember max/min Rx value case JCS_R_MOVE: // Set new Min's and Max's... // Set a new Center whenever either is hit! if( pdiJoyState->lRx > pRanges->jpMax.dwRx ) { pRanges->jpMax.dwRx = pdiJoyState->lRx; pRanges->jpCenter.dwRx = (pRanges->jpMax.dwRx+pRanges->jpMin.dwRx)>>1; } else if( pdiJoyState->lRx < pRanges->jpMin.dwRx ) { pRanges->jpMin.dwRx = pdiJoyState->lRx; pRanges->jpCenter.dwRx = (pRanges->jpMax.dwRx+pRanges->jpMin.dwRx)>>1; } // Do the position status // Update the text if( bShowRawData ) { myitoa(pdiJoyState->lRx, &tsz[0]); ::SendDlgItemMessage(hDlg, IDC_RAWXOUTPUT, WM_SETTEXT, 0, (LPARAM)(LPCTSTR)tsz); } if( bGradient ) pGradient->SetPos(pdiJoyState->lRx); ::PostMessage(ProgWndCal, PBM_SETPOS, (WPARAM)pdiJoyState->lRx, 0L); break; // remember max/min Ry value case JCS_U_MOVE: // Set new Min's and Max's... // Set a new Center whenever either is hit! if( pdiJoyState->lRy > pRanges->jpMax.dwRy ) { pRanges->jpMax.dwRy = pdiJoyState->lRy; pRanges->jpCenter.dwRy = (pRanges->jpMax.dwRy+pRanges->jpMin.dwRy)>>1; } else if( pdiJoyState->lRy < pRanges->jpMin.dwRy ) { pRanges->jpMin.dwRy = pdiJoyState->lRy; pRanges->jpCenter.dwRy = (pRanges->jpMax.dwRy+pRanges->jpMin.dwRy)>>1; } // Do the position status if( bShowRawData ) { myitoa(pdiJoyState->lRy, &tsz[0]); ::SendDlgItemMessage(hDlg, IDC_RAWXOUTPUT, WM_SETTEXT, 0, (LPARAM)(LPCTSTR)tsz); } if( bGradient ) pGradient->SetPos(pdiJoyState->lRy); ::PostMessage(ProgWndCal, PBM_SETPOS, (WPARAM)pdiJoyState->lRy, 0L); break; // remember max/min Rz value case JCS_V_MOVE: // Set new Min's and Max's... // Set a new Center whenever either is hit! if( pdiJoyState->lRz > pRanges->jpMax.dwRz ) { pRanges->jpMax.dwRz = pdiJoyState->lRz; pRanges->jpCenter.dwRz = (pRanges->jpMax.dwRz+pRanges->jpMin.dwRz)>>1; } else if( pdiJoyState->lRz < pRanges->jpMin.dwRz ) { pRanges->jpMin.dwRz = pdiJoyState->lRz; pRanges->jpCenter.dwRz = (pRanges->jpMax.dwRz+pRanges->jpMin.dwRz)>>1; } // Do the position status if( bShowRawData ) { myitoa(pdiJoyState->lRz, &tsz[0]); ::SendDlgItemMessage(hDlg, IDC_RAWXOUTPUT, WM_SETTEXT, 0, (LPARAM)(LPCTSTR)tsz); } if( bGradient ) pGradient->SetPos(pdiJoyState->lRz); ::PostMessage(ProgWndCal, PBM_SETPOS, (WPARAM)pdiJoyState->lRz, 0L); break; // remember max/min S0 value case JCS_S0_MOVE: // Set new Min's and Max's... // Set a new Center whenever either is hit! if( pdiJoyState->rglSlider[0] > pRanges->jpMax.dwS0 ) { pRanges->jpMax.dwS0 = pdiJoyState->rglSlider[0]; pRanges->jpCenter.dwS0 = (pRanges->jpMax.dwS0+pRanges->jpMin.dwS0)>>1; } else if( pdiJoyState->rglSlider[0] < pRanges->jpMin.dwS0 ) { pRanges->jpMin.dwS0 = pdiJoyState->rglSlider[0]; pRanges->jpCenter.dwS0 = (pRanges->jpMax.dwS0+pRanges->jpMin.dwS0)>>1; } // Do the position status if( bShowRawData ) { myitoa(pdiJoyState->rglSlider[0], &tsz[0]); ::SendDlgItemMessage(hDlg, IDC_RAWXOUTPUT, WM_SETTEXT, 0, (LPARAM)(LPCTSTR)tsz); } if( bGradient ) pGradient->SetPos(pdiJoyState->rglSlider[0]); ::PostMessage(ProgWndCal, PBM_SETPOS, (WPARAM)pdiJoyState->rglSlider[0], 0L); break; // remember max/min S1 value case JCS_S1_MOVE: // Set new Min's and Max's... // Set a new Center whenever either is hit! if( pdiJoyState->rglSlider[1] > pRanges->jpMax.dwS1 ) { pRanges->jpMax.dwS1 = pdiJoyState->rglSlider[1]; pRanges->jpCenter.dwS1 = (pRanges->jpMax.dwS1+pRanges->jpMin.dwS1)>>1; } else if( pdiJoyState->rglSlider[1] < pRanges->jpMin.dwS1 ) { pRanges->jpMin.dwS1 = pdiJoyState->rglSlider[1]; pRanges->jpCenter.dwS1 = (pRanges->jpMax.dwS1+pRanges->jpMin.dwS1)>>1; } // Do the position status if( bShowRawData ) { myitoa(pdiJoyState->rglSlider[1], &tsz[0]); ::SendDlgItemMessage(hDlg, IDC_RAWXOUTPUT, WM_SETTEXT, 0, (LPARAM)(LPCTSTR)tsz); } if( bGradient ) pGradient->SetPos(pdiJoyState->rglSlider[1]); ::PostMessage(ProgWndCal, PBM_SETPOS, (WPARAM)pdiJoyState->rglSlider[1], 0L); break; case JCS_POV_MOVEUP: case JCS_POV_MOVERIGHT: case JCS_POV_MOVEDOWN: case JCS_POV_MOVELEFT: // Do the position status /* if( bShowRawData ) { myitoa(pdiJoyState->rgdwPOV[0], &tsz[0]); ::SendDlgItemMessage(hDlg, IDC_RAWXOUTPUT, WM_SETTEXT, 0, (LPARAM)(LPCTSTR)tsz); } */ break; } return(TRUE); } // CollectCalInfo //******************************************************************************* // // FUNCTION: EnableXYWindows( HWND hDlg) // // PURPOSE: Enables X/Y Windows // // COMMENTS: // //******************************************************************************* void EnableXYWindows( HWND hDlg ) { ////// set up the XY window controls /////// USHORT nCtrls[] = {IDC_RAWX, IDC_RAWY, IDC_RAWXOUTPUT, IDC_RAWYOUTPUT}; BYTE nNumCtrls = sizeof(nCtrls)/sizeof(short); do { SetWindowPos( GetDlgItem( hDlg, nCtrls[--nNumCtrls]), NULL, NULL, NULL, NULL, NULL, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_HIDEWINDOW); } while( nNumCtrls ); #ifdef DEADZONE { USHORT nDZCtrls[] = {IDC_X_DEADZONE_SPIN, IDC_Y_DEADZONE_SPIN, IDC_X_SATURATION_SPIN, IDC_Y_SATURATION_SPIN, IDC_DEADZONE_TITLE, IDC_X_DEADZONE, IDC_Y_DEADZONE, IDC_X_AXIS_LABEL, IDC_X_AXIS_LABEL, IDC_Y_AXIS_LABEL, IDC_SATURATION_TITLE,IDC_X_SATURATION, IDC_Y_SATURATION, IDC_X_AXIS_LABEL_SATURATION, IDC_Y_AXIS_LABEL_SATURATION}; nNumCtrls = sizeof(nCtrls)/sizeof(short); do { // Use SetWindowPos here because internally, ShowWindow calls it! SetWindowPos( GetDlgItem( hDlg, nCtrls[nNumCtrls]), NULL, NULL, NULL, NULL, NULL, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | ((nCalState == JCS_DEADZONE) ? SWP_SHOWWINDOW : SWP_HIDEWINDOW)); } while( nNumCtrls-- ); } #endif // DEADZONE nCtrls[0] = IDC_JOYLIST1; nCtrls[1] = IDC_JOYLIST1_LABEL; nCtrls[2] = IDC_RAWDATA; nNumCtrls = 2; do { // Use SetWindowPos here because internally, ShowWindow calls it! SetWindowPos( GetDlgItem( hDlg, nCtrls[nNumCtrls]), NULL, NULL, NULL, NULL, NULL, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | (((nCalState == JCS_XY_MOVE) #ifdef DEADZONE || (nCalState == JCS_DEADZONE) #endif ) ? SWP_SHOWWINDOW : SWP_HIDEWINDOW)); } while( nNumCtrls-- ); HWND hwndXY = GetDlgItem(hDlg, IDC_JOYLIST1); // Disable RTL flag SetWindowLongPtr( hwndXY, GWL_EXSTYLE, GetWindowLongPtr(hwndXY,GWL_EXSTYLE) & ~WS_EX_LAYOUTRTL ); } //******************************************************************************* // // FUNCTION: GetOEMCtrlString(LPTSTR lptStr, BYTE *nStrLen) // // PURPOSE: Gets string and string length for OEM controls // // COMMENTS: // //******************************************************************************* BOOL GetOEMCtrlString(LPTSTR lptStr, LPDWORD nStrLen) { // there's no REGSTR_VAL_JOYOEM for the sliders so return false and take the defaults switch( nCalState ) { case JCS_S0_MOVE: case JCS_S1_MOVE: *nStrLen = 0; return(FALSE); } // Get the DIJOYCONFIG interface pointer! LPDIRECTINPUTJOYCONFIG pdiJoyConfig; pdiCpl->GetJoyConfig(&pdiJoyConfig); BOOL bRet = FALSE; if( SUCCEEDED(pdiJoyConfig->Acquire()) ) { HKEY hKey; // Open the TypeKey if( SUCCEEDED(pdiJoyConfig->OpenTypeKey( lpwszTypeName, KEY_ALL_ACCESS, &hKey)) ) { // registry strings for calibration messages static LPCTSTR pszOEMCalRegStrs[] = { REGSTR_VAL_JOYOEMCAL1, REGSTR_VAL_JOYOEMCAL2, REGSTR_VAL_JOYOEMCAL3, REGSTR_VAL_JOYOEMCAL4, REGSTR_VAL_JOYOEMCAL5, REGSTR_VAL_JOYOEMCAL6, REGSTR_VAL_JOYOEMCAL7, #ifdef WE_SUPPORT_CALIBRATING_POVS REGSTR_VAL_JOYOEMCAL8, REGSTR_VAL_JOYOEMCAL9, REGSTR_VAL_JOYOEMCAL10,REGSTR_VAL_JOYOEMCAL11, #endif // WE_SUPPORT_CALIBRATING_POVS REGSTR_VAL_JOYOEMCAL12 }; if( nCalState < (sizeof(pszOEMCalRegStrs)/sizeof(pszOEMCalRegStrs[0])) ) { DWORD dwType = REG_SZ; // the -2 is because of JCS_S0_MOVE and JCS_S1_MOVE! if( RegQueryValueEx( hKey, pszOEMCalRegStrs[(nCalState == JCS_FINI) ? nCalState-2 : nCalState], NULL, &dwType, (CONST LPBYTE)lptStr, nStrLen ) == ERROR_SUCCESS ) bRet = TRUE; else *nStrLen = 0; } else { *nStrLen = 0; } RegCloseKey(hKey); } else { *nStrLen = 0; #ifdef _DEBUG OutputDebugString(TEXT("Cal.cpp: GetOEMCtrlString: OpenTypeKey FAILED!\n")); #endif } pdiJoyConfig->Unacquire(); } return(bRet); } // *** end of GetOEMCtrlString #ifdef WE_SUPPORT_CALIBRATING_POVS /////////////////////////////////////////////////////////////////////////////////////////////////////// // // SetDefaultButton( HWND hwdb ) // ////////////////////////////////////////////////////////////////////////////////////////////////////// void SetDefaultButton( HWND hDlg, HWND hCtrl ) { // make the specified button the default DWORD style = GetWindowLong( hCtrl, GWL_STYLE ); style &= ~(BS_PUSHBUTTON|BS_DEFPUSHBUTTON); style |= BS_DEFPUSHBUTTON; SetWindowLong( hCtrl, GWL_STYLE, style ); } // SetDefaultButton #endif //WE_SUPPORT_CALIBRATING_POVS //=========================================================================== // SetCalibrationMode ( BOOL bSet ) // // Sets DirectInput Calibration mode (RAW/COOKED) // // Parameters: // BOOL bSet - TRUE for RAW, FALSE for COOKED // // Returns: return value from SetProperty (standard COM stuff) // //=========================================================================== HRESULT SetCalibrationMode( BOOL bSet) { DIPROPDWORD DIPropDword; DIPropDword.diph.dwSize = sizeof(DIPROPDWORD); DIPropDword.diph.dwHeaderSize = sizeof(DIPROPHEADER); DIPropDword.diph.dwObj = 0x0; DIPropDword.diph.dwHow = DIPH_DEVICE; DIPropDword.dwData = bSet ? DIPROPCALIBRATIONMODE_RAW : DIPROPCALIBRATIONMODE_COOKED; // Set the mode to Raw Data during Calibration! HRESULT hr = pdiDevice2->SetProperty(DIPROP_CALIBRATIONMODE, &DIPropDword.diph); #ifdef _DEBUG if( FAILED(hr) ) { OutputDebugString(TEXT("GCDEF.DLL: CAL.CPP: SetCalibrationMode: SetProperty Failed with a return of ")); switch( hr ) { case DI_PROPNOEFFECT: OutputDebugString(TEXT("DI_PROPNOEFFECT\n")); break; case DIERR_INVALIDPARAM: OutputDebugString(TEXT("DIERR_INVALIDPARAM\n")); break; case DIERR_OBJECTNOTFOUND: OutputDebugString(TEXT("DIERR_OBJECTNOTFOUND\n")); break; case DIERR_UNSUPPORTED: OutputDebugString(TEXT("DIERR_UNSUPPORTED\n")); break; default: { TCHAR szTmp[32]; wsprintf(szTmp, TEXT("%x"), hr); OutputDebugString(szTmp); } } } #endif return(hr); } //=========================================================================== // UpdateXYLabel(HWND hWnd) // // 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 // // Returns: // //=========================================================================== void UpdateXYLabel(const HWND hDlg) { BYTE nAxisFlags = pdiCpl->GetStateFlags()->nAxis; // X and Y use the same control so they are isolated! if( (nAxisFlags & HAS_X) || (nAxisFlags & HAS_Y) ) { LPDIDEVICEOBJECTINSTANCE_DX3 pDevObjInst = new (DIDEVICEOBJECTINSTANCE_DX3); assert (pDevObjInst); ZeroMemory(pDevObjInst, sizeof(DIDEVICEOBJECTINSTANCE_DX3)); pDevObjInst->dwSize = sizeof(DIDEVICEOBJECTINSTANCE_DX3); TCHAR ptszBuff[STR_LEN_32]; ZeroMemory(ptszBuff, sizeof(ptszBuff)); // Set it's text if( nAxisFlags & HAS_X ) { if( FAILED(pdiDevice2->GetObjectInfo((LPDIDEVICEOBJECTINSTANCE)pDevObjInst, DIJOFS_X, DIPH_BYOFFSET)) ) { #ifdef _DEBUG OutputDebugString(TEXT("GCDEF.DLL: DisplayAvailableAxis: GetObjectInfo Failed to find DIJOFS_X!\n")); #endif } int nLen=lstrlen(pDevObjInst->tszName)+1; if(nLen>STR_LEN_32) nLen=STR_LEN_32; StrCpyN(ptszBuff, pDevObjInst->tszName, nLen); // Set the Output Label! ::SendDlgItemMessage(hDlg, IDC_RAWX, WM_SETTEXT, 0, (LPARAM)(LPCTSTR)pDevObjInst->tszName); #ifdef DEADZONE // Set text labels! ::SendDlgItemMessage(hDlg, IDC_X_AXIS_LABEL_DEADZONE, WM_SETTEXT, 0, (LPARAM)(LPCTSTR)pDevObjInst->tszName); ::SendDlgItemMessage(hDlg, IDC_X_AXIS_LABEL_SATURATION, WM_SETTEXT, 0, (LPARAM)(LPCTSTR)pDevObjInst->tszName); #endif //DEADZONE // 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 } #ifdef DEADZONE // Set text labels! ::SendDlgItemMessage(hDlg, IDC_Y_AXIS_LABEL_DEADZONE, WM_SETTEXT, 0, (LPARAM)(LPCTSTR)pDevObjInst->tszName); ::SendDlgItemMessage(hDlg, IDC_Y_AXIS_LABEL_SATURATION, WM_SETTEXT, 0, (LPARAM)(LPCTSTR)pDevObjInst->tszName); #endif //DEADZONE // just in case it has Y but not X if( ptszBuff && lstrlen(ptszBuff) ) { // Whisltler PREFIX 45092 int nLen=STR_LEN_32-lstrlen(ptszBuff); StrNCat(ptszBuff, TEXT(" / "), nLen); } int nLen=STR_LEN_32-lstrlen(ptszBuff); StrNCat(ptszBuff, pDevObjInst->tszName, nLen); // Set the Output Label! ::SendDlgItemMessage(hDlg, IDC_RAWY, WM_SETTEXT, 0, (LPARAM)(LPCTSTR)pDevObjInst->tszName); // Remove the HAS_Y flag nAxisFlags &= ~HAS_Y; } if( pDevObjInst ) delete (pDevObjInst); ::SendDlgItemMessage(hDlg, IDC_JOYLIST1_LABEL, WM_SETTEXT, 0, (LPARAM)(LPCTSTR)ptszBuff); } } //*** end of UpdateXYLabel //******************************************************************************* // // FUNCTION: UpdateProgressLabel(HWND hDlg) // // PURPOSE: Updates Axis specific labels based on the current Calibration stage. // // COMMENTS: // //******************************************************************************* BOOL UpdateProgressLabel(const HWND hDlg) { // Array of supported axis! const DWORD dwOffsetArray[] = {DIJOFS_Z, DIJOFS_RX, DIJOFS_RY, DIJOFS_RZ, DIJOFS_SLIDER(0), DIJOFS_SLIDER(1)}; BOOL bRet = FALSE; DIDEVICEOBJECTINSTANCE_DX3 DevObjInst; ZeroMemory(&DevObjInst, sizeof(DIDEVICEOBJECTINSTANCE_DX3)); DevObjInst.dwSize = sizeof(DIDEVICEOBJECTINSTANCE_DX3); // Get it's text if( SUCCEEDED(pdiDevice2->GetObjectInfo((LPDIDEVICEOBJECTINSTANCE)&DevObjInst, dwOffsetArray[nCalState-3], DIPH_BYOFFSET)) ) { // Set it's text ::SendDlgItemMessage(hDlg, IDC_JOYLIST2_LABEL, WM_SETTEXT, 0, (LPARAM)(LPCTSTR)DevObjInst.tszName); ::SendDlgItemMessage(hDlg, IDC_RAWX, WM_SETTEXT, 0, (LPARAM)(LPCTSTR)DevObjInst.tszName); bRet = TRUE; } return(bRet); } /////////////////////////////////////////////////////////////////////////////// // FUNCTION: myitoa(long n, LPTSTR lpStr) // // PARAMETERS: BYTE n - Number to be translated // LPTSTR lpStr - Buffer to recieve translated value // // PURPOSE: Convert BYTE values < 20 to strings. /////////////////////////////////////////////////////////////////////////////// void myitoa(long n, LPTSTR lpStr) { long sign = n; if( n < 0 ) n = - n; LPTSTR pchStart = lpStr; do { *lpStr++ = (TCHAR)(n % 10 + '0'); } while( (n /= 10) > 0 ); if( sign < 0 ) *lpStr++ = '-'; *lpStr = '\0'; reverse(pchStart); } void reverse(LPTSTR string) { TCHAR c; short i, j; for( i = 0, j = lstrlen(string) - 1; i < j; i++, j-- ) { c = string[j]; string[j] = string[i]; string[i] = c; } } //******************************************************************************* // // FUNCTION: RawDataSelected( HWND hWnd, BOOL bEnable ) // // PURPOSE: Shows/Hides Raw data associated windows. // // COMMENTS: // //******************************************************************************* void RawDataSelected( const HWND hWnd, BOOL bEnable ) { const USHORT nCtrlArray[] = {IDC_RAWX, IDC_RAWY, IDC_RAWXOUTPUT, IDC_RAWYOUTPUT}; BYTE nCtrls = sizeof(nCtrlArray)/sizeof(short); do { SetWindowPos( GetDlgItem( hWnd, nCtrlArray[--nCtrls]), NULL, NULL, NULL, NULL, NULL, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | ((bEnable) ? SWP_SHOWWINDOW : SWP_HIDEWINDOW)); } while( nCtrls ); } //******************************************************************************* // // FUNCTION: TimerProc(HWND hWnd, UINT uMsg, UINT idEvent, DWORD dwTime) // // PURPOSE: TimerProc for the Calibration Wizard. // Searches for button presses, then moves to next stage/finish. // // COMMENTS: // //******************************************************************************* VOID CALLBACK TimerProc(const HWND hWnd, UINT uMsg, UINT idEvent, DWORD dwTime) { if( SUCCEEDED(DIUtilPollJoystick(pdiDevice2, lpDIJoyState)) ) { CollectCalInfo(hWnd, lpDIJoyState); // Don't bother checking for key presses if the user is in the POV stage! if( nCalState <= JCS_S1_MOVE ) { // Catch button presses... static BYTE nDownButton = 0xff; BYTE i = 0; int nButtons = pdiCpl->GetStateFlags()->nButtons; // only attempt to check buttons we KNOW we have!!! while( nButtons ) { // check for a button press if( lpDIJoyState->rgbButtons[i] & 0x80 ) { if( nDownButton != 0xff ) break; // Let the Next button handle the processing ::PostMessage(GetParent(hWnd), PSM_PRESSBUTTON, (WPARAM)(int)(nCalState > JCS_S1_MOVE) ? PSBTN_FINISH : PSBTN_NEXT, 0); // Store the button that went down! nDownButton = i; // mission accomplished! return; } // reset the nDownButton flag else if( i == nDownButton ) nDownButton = 0xff; nButtons &= ~(HAS_BUTTON1<GetStateFlags()->nAxis); LPDIRECTINPUTJOYCONFIG pdiJoyConfig; pdiCpl->GetJoyConfig(&pdiJoyConfig); if( pdiCpl->GetStateFlags()->nPOVs ) { pdiDevice2->Unacquire(); SetCalibrationMode( FALSE ); pdiJoyConfig->Acquire(); CopyRange( &pJoyConfig->hwc.hwv.jrvHardware, pRanges ); memcpy( pJoyConfig->hwc.hwv.dwPOVValues, pRanges->dwPOV, sizeof(DWORD)*4 ); hres = pdiJoyConfig->SetConfig(pdiCpl->GetID(), (LPDIJOYCONFIG)pJoyConfig, DIJC_REGHWCONFIGTYPE); #ifdef WE_SUPPORT_CALIBRATING_POVS if( SUCCEEDED(hres) ) { CalibratePolledPOV( &pJoyConfig->hwc ); // set POV positions! if( bPolledPOV ) { SetMyPOVRanges(pdiDevice2); } } #endif } pdiJoyConfig->SendNotify(); pdiDevice2->Unacquire(); }