//**************************************************************************** // // File: joycpl.c // Content: Joystick configuration and testing // History: // Date By Reason // ==== == ====== // 03-oct-94 craige initial implementation // 05-nov-94 craige generalized 4 axis joysticks and other improvements // 11-nov-94 craige allow multiple copies of tab to run // 22-nov-94 craige tweaks to calibration code // 29-nov-94 craige small bugs // 08-dec-94 craige generalized second joystick // 11-dec-94 craige split into component parts // 15-dec-94 craige allow N joysticks // 18-dec-94 craige process UV // 05-jan-95 craige external rudder bug // 05-mar-95 craige Bug 9998: pass id -1 to get base dev caps // Bug 15334: allow reset of user values for compatiblity // 06-mar-95 craige Bug 7608: deleting VxD name if joystick not present // caused unplugged joystick to never come back // 06-may-96 richj ported to NT // // Copyright (c) Microsoft Corporation 1994 // //**************************************************************************** #include "joycpl.h" extern HINSTANCE hInstance; // main.c #define cchLENGTH(_sz) (sizeof(_sz)/sizeof(_sz[0])) #define GetString(_sz,_ids) LoadString (hInstance, _ids, _sz, cchLENGTH(_sz)) #ifdef DEBUG void cdecl MBOX(LPSTR szFormat, ...) { char ach[256]; wvsprintf( ach,szFormat,(LPSTR)(&szFormat+1)); MessageBox( NULL, ach, "JOYCPL", MB_OK | MB_SYSTEMMODAL ); } #endif /*************************************************************************** MEMORY MANAGEMENT ROUTINES FOLLOW ***************************************************************************/ #ifdef DEBUG DWORD allocCount; #endif /* * DoAlloc - allocate memory */ LPVOID DoAlloc( DWORD size ) { LPVOID res; res = LocalAlloc( LPTR, size ); #ifdef DEBUG allocCount++; #endif return res; } /* DoAlloc */ /* * DoFree - free allocated memory */ void DoFree( LPVOID ptr ) { if( ptr != NULL ) { LocalFree( ptr ); #ifdef DEBUG allocCount--; if( allocCount < 0 ) { DPF( "JOYCPL: Too many frees, allocCount=%d\r\n", allocCount ); } #endif } } /* DoFree */ /*************************************************************************** REGISTRY RELATED ROUTINES FOLLOW ***************************************************************************/ /* * getDevCaps - get the joystick device caps */ static void getDevCaps( LPGLOBALVARS pgv ) { JOYCAPS jc; if( joyGetDevCaps( pgv->iJoyId, &jc, sizeof( jc ) ) == JOYERR_NOERROR ) { pgv->joyRange.jpMin.dwX = jc.wXmin; pgv->joyRange.jpMax.dwX = jc.wXmax; pgv->joyRange.jpMin.dwY = jc.wYmin; pgv->joyRange.jpMax.dwY = jc.wYmax; pgv->joyRange.jpMin.dwZ = jc.wZmin; pgv->joyRange.jpMax.dwZ = jc.wZmax; pgv->joyRange.jpMin.dwR = jc.wRmin; pgv->joyRange.jpMax.dwR = jc.wRmax; pgv->joyRange.jpMin.dwU = jc.wUmin; pgv->joyRange.jpMax.dwU = jc.wUmax; pgv->joyRange.jpMin.dwV = jc.wVmin; pgv->joyRange.jpMax.dwV = jc.wVmax; pgv->dwMaxAxes = (DWORD) jc.wMaxAxes; } } /* getDevCaps */ extern MMRESULT WINAPI joyConfigChanged( DWORD dwFlags ); /* * RegistryUpdated - notify the driver that the registry is updated */ void RegistryUpdated( LPGLOBALVARS pgv ) { joyConfigChanged( 0 ); if( pgv != NULL ) { getDevCaps( pgv ); // devcaps could change } } /* RegistryUpdated */ /* * createSettingsKeyFromCurr - create a settings key for a specific joystick */ static void createSettingsKeyFromCurr( LPGLOBALVARS pgv, LPSTR str ) { char tmp[MAX_STR]; int type; LPJOYDATA pjd; pjd = pgv->pjd; if( pgv->joyHWCurr.dwUsageSettings & JOY_US_ISOEM ) { type = pgv->joyHWCurr.dwType - JOY_HW_LASTENTRY; if( type < 0 || type >= pjd->oemCount ) { tmp[0] = 0; } else { strcpy( tmp, pjd->oemList[type].keyname ); } } else { wsprintf( tmp, "predef%d", pgv->joyHWCurr.dwType ); } wsprintf( str, "%s\\%s", pjd->regSettingsCfgKey, tmp ); } /* createSettingsKeyFromCurr */ /* * regSaveSpecificJoyHW - save specific joystick hardware config. to the registry */ static void regSaveSpecificJoyHW( LPGLOBALVARS pgv ) { char str[MAX_STR]; HKEY hkey; char jcfg[MAX_STR]; if( pgv->joyHWCurr.dwType == JOY_HW_NONE ) { return; } if( !(pgv->joyActiveFlags & HASJOY) ) { return; } createSettingsKeyFromCurr( pgv, str ); if( !RegCreateKey( HKEY_LOCAL_MACHINE, str, &hkey ) ) { GETKEYNAME( pgv, jcfg, REGSTR_VAL_JOYNCONFIG ); RegSetValueEx( hkey, jcfg, 0, REG_BINARY, (CONST LPBYTE)&pgv->joyHWCurr, sizeof( pgv->joyHWCurr )); RegCloseKey( hkey ); } } /* regSaveSpecificJoyHW */ /* * regCreateCurrKey - create the current joystick settings key */ static HKEY regCreateCurrKey( LPGLOBALVARS pgv ) { HKEY hkey; if( !RegCreateKey( HKEY_LOCAL_MACHINE, pgv->pjd->regCurrCfgKey, &hkey ) ) { return hkey; } else { return NULL; } } /* regCreateCurrKey */ /* * RegSaveCurrentJoyHW - save the joystick info to the current entry in * the registry */ void RegSaveCurrentJoyHW( LPGLOBALVARS pgv ) { HKEY hkey; LPSTR sptr; char vname[MAX_STR]; char oname[MAX_STR]; char coname[MAX_STR]; int type; LPJOYDATA pjd; if( pgv->joyHWCurr.dwType == JOY_HW_NONE ) { return; } if( !(pgv->joyActiveFlags & HASJOY) ) { return; } hkey = regCreateCurrKey( pgv ); if( hkey == NULL ) { DPF( "Could not save current joystick settings!\r\n" ); return; } pjd = pgv->pjd; if( pgv->joyHWCurr.dwUsageSettings & JOY_US_ISOEM ) { sptr = pjd->oemList[ pgv->joyHWCurr.dwType - JOY_HW_LASTENTRY ].keyname; } GETKEYNAME( pgv, vname, REGSTR_VAL_JOYNCONFIG ); GETKEYNAME( pgv, oname, REGSTR_VAL_JOYNOEMNAME ); GETKEYNAME( pgv, coname, REGSTR_VAL_JOYNOEMCALLOUT ); RegSetValueEx( hkey, vname, 0, REG_BINARY, (CONST LPBYTE)&pgv->joyHWCurr, sizeof( pgv->joyHWCurr ) ); if( pgv->joyHWCurr.dwUsageSettings & JOY_US_ISOEM ) { RegSetValueEx( hkey, oname, 0, REG_SZ, sptr, strlen( sptr ) + 1 ); /* * set up VxD name for this joystick */ type = pgv->joyHWCurr.dwType - JOY_HW_LASTENTRY; if( (pjd->oemList[type].vxd_name[0] != 0) ) { RegSetValueEx( hkey, coname, 0, REG_SZ, pjd->oemList[type].vxd_name, strlen( pjd->oemList[type].vxd_name )+1 ); } else { RegDeleteValue( hkey, coname ); } } else { RegDeleteValue( hkey, oname ); RegDeleteValue( hkey, coname ); } RegCloseKey( hkey ); } /* RegSaveCurrentJoyHW */ /* * regPermSaveAllInfo - save joystick data to the registry for good */ static void regPermSaveAllInfo( LPGLOBALVARS pgv ) { // save specific hardware settings to the registry regSaveSpecificJoyHW( pgv ); // save current current hardware to the registry RegSaveCurrentJoyHW( pgv ); RegistryUpdated( pgv ); } /* regPermSaveAllInfo */ /* * setHWCurrType - set the current hardware type (check for OEM type) */ static BOOL setHWCurrType( LPGLOBALVARS pgv, HKEY hkey, LPJOYREGHWCONFIG pcfg ) { char str[MAX_STR]; char pname[MAX_STR]; int i; DWORD regtype; DWORD cb; LPJOYDATA pjd; if( !(pcfg->dwUsageSettings & JOY_US_ISOEM) ) { return TRUE; } GETKEYNAME( pgv, pname, REGSTR_VAL_JOYNOEMNAME ); cb = sizeof( str ); if( RegQueryValueEx( hkey, pname, NULL, ®type, (CONST LPBYTE)str, &cb)) { return FALSE; } if( regtype != REG_SZ ) { return FALSE; } pjd = pgv->pjd; for( i=0;ioemCount;i++ ) { if( !_stricmp( str, pjd->oemList[i].keyname ) ) { pcfg->dwType = i + JOY_HW_LASTENTRY; return TRUE; } } return FALSE; } /* setHWCurrType */ /* * regGetCurrHW - get the information about the current configuration * from the registry */ static void regGetCurrHW( LPGLOBALVARS pgv ) { DWORD regtype; DWORD cb; JOYREGHWCONFIG config; HKEY hkey; char str[MAX_STR]; JOYCAPS jc; pgv->joyHWCurr = pgv->pjd->joyHWDefaults[ JOY_HW_NONE ]; // Give the joystick driver a chance to write its current settings, // if there are none. // joyGetDevCaps( pgv->iJoyId, &jc, sizeof( jc ) ); // Read those current settings (if they exist), and use them to determine // what type of joystick we've got // if ((hkey = regCreateCurrKey (pgv)) != NULL) { cb = sizeof( config ); GETKEYNAME( pgv, str, REGSTR_VAL_JOYNCONFIG ); if( !RegQueryValueEx( hkey, str, NULL, ®type, (CONST LPBYTE)&config, &cb)) { if( regtype == REG_BINARY && cb == sizeof( config ) ) { if( setHWCurrType( pgv, hkey, &config ) ) { pgv->joyHWCurr = config; } } } RegCloseKey( hkey ); } // Does this joystick match a known type? // if (pgv->joyHWCurr.hws.dwNumButtons != 0) { int ii; for ( ii=0;iipjd->oemCount;ii++ ) { if ( (pgv->pjd->oemList[ii].hws.dwFlags == pgv->joyHWCurr.hws.dwFlags) && (pgv->pjd->oemList[ii].hws.dwNumButtons == pgv->joyHWCurr.hws.dwNumButtons) ) { pgv->joyHWCurr.dwType = ii + JOY_HW_LASTENTRY; break; } } if (pgv->joyHWCurr.dwType == JOY_HW_NONE) { pgv->joyHWCurr.dwType = JOY_HW_CUSTOM; } } } /* regGetCurrHW */ /* * regGetOEMStr - get an OEM string */ static BOOL regGetOEMStr( HKEY hkey, LPSTR keyname, LPSTR buff, int size, LPSTR *res ) { DWORD cb; DWORD type; LPSTR str; int slen; cb = size; slen = 1; if( !RegQueryValueEx( hkey, keyname, NULL, &type, (CONST LPBYTE)buff, &cb ) ) { if( type == REG_SZ ) { slen = strlen( buff ) + 1; } } str = DoAlloc( slen ); if( str != NULL ) { if( slen == 1 ) { str[0] = 0; } else { strcpy( str, buff ); } } *res = str; if( str == NULL ) { return TRUE; } return FALSE; } /* regGetOEMStr */ /* * checkNonStandardUserVals */ static BOOL checkNonStandardUserVals( LPJOYREGUSERVALUES puv ) { if( (puv->jrvRanges.jpMin.dwX != RANGE_MIN) || (puv->jrvRanges.jpMin.dwY != RANGE_MIN) || (puv->jrvRanges.jpMin.dwZ != RANGE_MIN) || (puv->jrvRanges.jpMin.dwR != RANGE_MIN) || (puv->jrvRanges.jpMin.dwU != RANGE_MIN) || (puv->jrvRanges.jpMin.dwV != RANGE_MIN) || (puv->jrvRanges.jpMax.dwX != RANGE_MAX) || (puv->jrvRanges.jpMax.dwY != RANGE_MAX) || (puv->jrvRanges.jpMax.dwZ != RANGE_MAX) || (puv->jrvRanges.jpMax.dwR != RANGE_MAX) || (puv->jrvRanges.jpMax.dwU != RANGE_MAX) || (puv->jrvRanges.jpMax.dwV != RANGE_MAX) || (puv->dwTimeOut != 0x1000) || (puv->jpDeadZone.dwX != 0) || (puv->jpDeadZone.dwY != 0) ) { return TRUE; } return FALSE; } /* checkNonStandardUserVals */ /* * regSetUserVals - set user values to our defaults */ static void regSetUserVals( LPJOYDATA pjd, BOOL retest ) { JOYREGUSERVALUES uv; JOYREGUSERVALUES ouv; HKEY hkey; DWORD regtype; DWORD cb; if( !RegOpenKey( HKEY_LOCAL_MACHINE, pjd->regCfgKey, &hkey ) ) { /* * build the default settings */ memset( &uv, 0, sizeof( uv ) ); uv.dwTimeOut = 0x1000; uv.jpDeadZone.dwX = 0; uv.jpDeadZone.dwY = 0; uv.jrvRanges.jpMin.dwX = RANGE_MIN; uv.jrvRanges.jpMin.dwY = RANGE_MIN; uv.jrvRanges.jpMin.dwZ = RANGE_MIN; uv.jrvRanges.jpMin.dwR = RANGE_MIN; uv.jrvRanges.jpMin.dwU = RANGE_MIN; uv.jrvRanges.jpMin.dwV = RANGE_MIN; uv.jrvRanges.jpMax.dwX = RANGE_MAX; uv.jrvRanges.jpMax.dwY = RANGE_MAX; uv.jrvRanges.jpMax.dwZ = RANGE_MAX; uv.jrvRanges.jpMax.dwR = RANGE_MAX; uv.jrvRanges.jpMax.dwU = RANGE_MAX; uv.jrvRanges.jpMax.dwV = RANGE_MAX; if( retest ) { /* * see if the values have changed since we last set them: * if yes, then we need to reset our remembered values */ DPF( "Looking for USER entries\r\n" ); cb = sizeof( ouv ); if( !RegQueryValueEx( hkey, REGSTR_VAL_JOYUSERVALUES, NULL, ®type, (CONST LPBYTE)&ouv, &cb)) { DPF( "found REGSTR_VAL_JOYUSERVALUES\r\n" ); if( regtype == REG_BINARY && cb == sizeof( ouv ) ) { if( memcmp( &uv, &ouv, sizeof( uv ) ) ) { DPF( "USER entries changed!\r\n" ); pjd->bHasUserVals = TRUE; pjd->bDeleteUserVals = FALSE; pjd->userVals = ouv; } } } else { if( pjd->bHasUserVals ) { DPF( "USER entries changed, no longer exist!\r\n" ); pjd->bHasUserVals = FALSE; pjd->bDeleteUserVals = TRUE; } } } /* * set our new values */ RegSetValueEx( hkey, REGSTR_VAL_JOYUSERVALUES, 0, REG_BINARY, (CONST LPBYTE)&uv, sizeof( uv ) ); RegCloseKey( hkey ); } } /* regSetUserVals */ /* * regUserValsInit - save old user values, and init to ones we like */ static void regUserValsInit( LPJOYDATA pjd ) { HKEY hkey; DWORD regtype; DWORD cb; pjd->bHasUserVals = FALSE; pjd->bDeleteUserVals = FALSE; if( !RegOpenKey( HKEY_LOCAL_MACHINE, pjd->regCfgKey, &hkey ) ) { cb = sizeof( pjd->userVals ); if( !RegQueryValueEx( hkey, REGSTR_VAL_JOYUSERVALUES, NULL, ®type, (CONST LPBYTE)&pjd->userVals, &cb)) { if( regtype == REG_BINARY && cb == sizeof( pjd->userVals ) ) { pjd->bHasUserVals = TRUE; DPF( "USER entries exist!\r\n" ); } pjd->bHasNonStandardUserVals = checkNonStandardUserVals( &pjd->userVals ); } else { pjd->bDeleteUserVals = TRUE; pjd->bHasNonStandardUserVals = FALSE; DPF( "USER entries don't exist!\r\n" ); } RegCloseKey( hkey ); } regSetUserVals( pjd, FALSE ); } /* regUserValsInit */ /* * regUserValsFini - restore old user values */ static void regUserValsFini( LPJOYDATA pjd ) { HKEY hkey; if( pjd->bResetUserVals ) { RegDeleteValue( hkey, REGSTR_VAL_JOYUSERVALUES ); RegistryUpdated( NULL ); } else if( pjd->bHasUserVals || pjd->bDeleteUserVals ) { if( !RegOpenKey( HKEY_LOCAL_MACHINE, pjd->regCfgKey, &hkey ) ) { if( pjd->bHasUserVals ) { DPF( "resetting USER entries!\r\n" ); RegSetValueEx( hkey, REGSTR_VAL_JOYUSERVALUES, 0, REG_BINARY, (CONST LPBYTE)&pjd->userVals, sizeof( pjd->userVals ) ); } else { DPF( "deleting USER entries!\r\n" ); RegDeleteValue( hkey, REGSTR_VAL_JOYUSERVALUES ); } RegistryUpdated( NULL ); } pjd->bHasUserVals = FALSE; pjd->bDeleteUserVals = FALSE; } } /* regUserValsFini */ /*************************************************************************** CUSTOM JOYSTICK SELECTION FUNCTIONS FOLLOW ***************************************************************************/ /* * custom joystick variables */ typedef struct { LPGLOBALVARS pgv; BOOL bHasZ; BOOL bHasR; BOOL bHasPOV; BOOL bIsYoke; BOOL bIsGamePad; BOOL bIsCarCtrl; BOOL bHas2Buttons; } cust_vars, *LPCUSTVARS; /* * enableCustomSpecial - enable the special section of the custom dialog box */ static void enableCustomSpecial( HWND hwnd, BOOL on ) { EnableWindow( GetDlgItem( hwnd, IDC_JOYISYOKE ), on ); EnableWindow( GetDlgItem( hwnd, IDC_JOYISGAMEPAD ), on ); EnableWindow( GetDlgItem( hwnd, IDC_JOYISCARCTRL ), on ); CheckDlgButton( hwnd, IDC_JOYUSESPECIAL, on ); if( !on ) { CheckDlgButton( hwnd, IDC_JOYISYOKE, FALSE ); CheckDlgButton( hwnd, IDC_JOYISGAMEPAD, FALSE ); CheckDlgButton( hwnd, IDC_JOYISCARCTRL, FALSE ); } } /* enableCustomSpecial */ /* * context help for the custom settings dialog */ const static DWORD aCustomHelpIDs[] = { // Context Help IDs IDC_GROUPBOX, IDH_JOYSTICK_CUSTOM_AXES, IDC_GROUPBOX_2, IDH_JOYSTICK_CUSTOM_BUTTONS, IDC_GROUPBOX_3, IDH_JOYSTICK_GROUPBOX, IDC_JOY2AXIS, IDH_JOYSTICK_CUSTOM_AXES, IDC_JOY3AXIS, IDH_JOYSTICK_CUSTOM_AXES, IDC_JOY4AXIS, IDH_JOYSTICK_CUSTOM_AXES, IDC_JOY2BUTTON, IDH_JOYSTICK_CUSTOM_BUTTONS, IDC_JOY4BUTTON, IDH_JOYSTICK_CUSTOM_BUTTONS, IDC_JOYHASPOV, IDH_JOYSTICK_CUSTOM_POV_HAT, IDC_JOYISYOKE, IDH_JOYSTICK_CUSTOM_FLIGHT_YOKE, IDC_JOYISGAMEPAD, IDH_JOYSTICK_CUSTOM_GAME_PAD, IDC_JOYISCARCTRL, IDH_JOYSTICK_CUSTOM_CAR_CONTROL, IDC_JOYUSESPECIAL, IDH_JOYSTICK_CUSTOM_CUSTOM_FEATURES, 0, 0 }; /* * CustomProc - callback procedure for custom joystick setup */ BOOL CALLBACK CustomProc( HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lParam) { int id; LPGLOBALVARS pgv; LPCUSTVARS pcv; switch( umsg ) { case WM_DESTROY: /* * don't free the dialog's variables here, they are returned to the * creator; the creator will free them */ break; case WM_INITDIALOG: /* * create variables for the custom dialog */ pcv = DoAlloc( sizeof( cust_vars ) ); SetWindowLong( hwnd, DWL_USER, (LONG) pcv ); if( pcv == NULL ) { EndDialog( hwnd, 0 ); return FALSE; } pgv = (LPGLOBALVARS) lParam; pcv->pgv = pgv; /* * set up initial dialog state */ pcv->bHasZ = (pgv->joyHWCurr.hws.dwFlags & JOY_HWS_HASZ); pcv->bHasR = (pgv->joyHWCurr.hws.dwFlags & JOY_HWS_HASR); pcv->bHas2Buttons = (pgv->joyHWCurr.hws.dwNumButtons == 2); pcv->bHasPOV = (pgv->joyHWCurr.hws.dwFlags & JOY_HWS_HASPOV); pcv->bIsYoke = (pgv->joyHWCurr.hws.dwFlags & JOY_HWS_ISYOKE); pcv->bIsGamePad = (pgv->joyHWCurr.hws.dwFlags & JOY_HWS_ISGAMEPAD); pcv->bIsCarCtrl = (pgv->joyHWCurr.hws.dwFlags & JOY_HWS_ISCARCTRL); if( pcv->bHasZ && pcv->bHasR ) { CheckRadioButton( hwnd, IDC_JOY2AXIS, IDC_JOY4AXIS, IDC_JOY4AXIS ); } else if( pcv->bHasZ ) { CheckRadioButton( hwnd, IDC_JOY2AXIS, IDC_JOY4AXIS, IDC_JOY3AXIS ); } else { CheckRadioButton( hwnd, IDC_JOY2AXIS, IDC_JOY4AXIS, IDC_JOY2AXIS ); } if( pcv->bHas2Buttons ) { CheckRadioButton( hwnd, IDC_JOY2BUTTON, IDC_JOY4BUTTON, IDC_JOY2BUTTON ); } else { CheckRadioButton( hwnd, IDC_JOY2BUTTON, IDC_JOY4BUTTON, IDC_JOY4BUTTON ); } CheckDlgButton( hwnd, IDC_JOYHASPOV, pcv->bHasPOV ); id = -1; if( pcv->bIsYoke ) { id = IDC_JOYISYOKE; } else if( pcv->bIsGamePad ) { id = IDC_JOYISGAMEPAD; } else if( pcv->bIsCarCtrl ) { id = IDC_JOYISCARCTRL; } if( id != -1 ) { enableCustomSpecial( hwnd, TRUE ); CheckRadioButton( hwnd, IDC_JOYISYOKE, IDC_JOYISCARCTRL, id ); } else { enableCustomSpecial( hwnd, FALSE ); } return FALSE; case WM_HELP: WinHelp((HWND)((LPHELPINFO) lParam)->hItemHandle, cszHelpFile, HELP_WM_HELP, (DWORD)(LPSTR) aCustomHelpIDs); return TRUE; case WM_CONTEXTMENU: WinHelp((HWND) wParam, cszHelpFile, HELP_CONTEXTMENU, (DWORD)(LPVOID) aCustomHelpIDs); return TRUE; case WM_COMMAND: pcv = (LPCUSTVARS) GetWindowLong( hwnd, DWL_USER ); id = GET_WM_COMMAND_ID(wParam, lParam); switch( id ) { case IDC_JOY2AXIS: case IDC_JOY3AXIS: case IDC_JOY4AXIS: CheckRadioButton( hwnd, IDC_JOY2AXIS, IDC_JOY4AXIS, id ); pcv->bHasZ = FALSE; pcv->bHasR = FALSE; if( id == IDC_JOY3AXIS ) { pcv->bHasZ = TRUE; } else if( id == IDC_JOY4AXIS ) { pcv->bHasZ = TRUE; pcv->bHasR = TRUE; } break; case IDC_JOY2BUTTON: case IDC_JOY4BUTTON: CheckRadioButton( hwnd, IDC_JOY2BUTTON, IDC_JOY4BUTTON, id ); pcv->bHas2Buttons = (id == IDC_JOY2BUTTON); break; case IDC_JOYUSESPECIAL: enableCustomSpecial( hwnd, IsDlgButtonChecked( hwnd, IDC_JOYUSESPECIAL ) ); pcv->bIsYoke = FALSE; pcv->bIsGamePad = FALSE; pcv->bIsCarCtrl = FALSE; break; case IDC_JOYHASPOV: pcv->bHasPOV = !pcv->bHasPOV; break; case IDC_JOYISYOKE: case IDC_JOYISGAMEPAD: case IDC_JOYISCARCTRL: pcv->bIsYoke = (id == IDC_JOYISYOKE); pcv->bIsGamePad = (id == IDC_JOYISGAMEPAD); pcv->bIsCarCtrl = (id == IDC_JOYISCARCTRL); CheckRadioButton( hwnd, IDC_JOYISYOKE, IDC_JOYISCARCTRL, id ); break; case IDCANCEL: pcv = (LPCUSTVARS) GetWindowLong( hwnd, DWL_USER ); DoFree( pcv ); EndDialog( hwnd, 0 ); break; case IDOK: pcv = (LPCUSTVARS) GetWindowLong( hwnd, DWL_USER ); EndDialog(hwnd, (int) pcv ); break; } break; default: break; } return FALSE; } /* CustomProc */ /*************************************************************************** MAIN DIALOG FUNCTIONS FOLLOW ***************************************************************************/ /* * variables used by joystick tab dialog */ typedef struct { LPGLOBALVARS pgv; } JTVARS, *LPJTVARS; /* * numJoyAxes - get number of axes on a joystick */ static int numJoyAxes( LPGLOBALVARS pgv ) { DWORD flags; int axis_count; flags = pgv->joyHWCurr.hws.dwFlags; axis_count = 2; if( flags & JOY_HWS_HASZ ) { axis_count++; } if( flags & JOY_HWS_HASR ) { axis_count++; } if( (flags & JOY_HWS_HASPOV) && (flags & JOY_HWS_POVISPOLL) ) { axis_count++; } return axis_count; } /* numJoyAxes */ /* * saveHWSettings - save the current hardware settings */ static void saveHWSettings( LPGLOBALVARS pgv ) { pgv->joyHWOrig = pgv->joyHWCurr; } /* saveHWSettings */ /* * restoreHWSettings - restore current hw settings to saved values */ static void restoreHWSettings( LPGLOBALVARS pgv ) { pgv->joyHWCurr = pgv->joyHWOrig; RegSaveCurrentJoyHW( pgv ); } /* restoreHWSettings */ /* * getActiveFlags - poll and test which joysticks are currently plugged in */ static unsigned getActiveFlags( LPGLOBALVARS pgv ) { JOYINFOEX ji; MMRESULT rc; unsigned val; /* * check for presense of joystick 1 and joystick 2 */ val = 0; ji.dwSize = sizeof( ji ); ji.dwFlags = JOY_RETURNX|JOY_RETURNY|JOY_CAL_READXYONLY|JOY_CAL_READALWAYS; rc = joyGetPosEx( pgv->iJoyId, &ji ); DPF( "joyGetPosEx = %d\r\n", rc ); if( rc == JOYERR_NOERROR ) { val = HASJOY; } /* * check if either could have a rudder attached. */ ji.dwFlags = JOY_RETURNR | JOY_CAL_READRONLY; if( (numJoyAxes( pgv ) < 4) && !(pgv->joyHWCurr.hws.dwFlags & JOY_HWS_HASR ) ) { rc = joyGetPosEx( pgv->iJoyId, &ji ); if( rc ==JOYERR_NOERROR ) { val |= HASRUDDERMAYBE; } } return val; } /* getActiveFlags */ /* * enableTestCal - enable/disable test and calibrate buttons */ static void enableTestCal( HWND hwnd, int hw_type ) { BOOL enable; enable = (hw_type != JOY_HW_NONE); EnableWindow( GetDlgItem( hwnd, IDC_JOYCALIBRATE ), enable ); EnableWindow( GetDlgItem( hwnd, IDC_JOYTEST ), enable ); } /* enableTestCal */ /* * cleanUpJoyDlg - clean up allocated stuff */ static void cleanUpJoyDlg( HWND hwnd ) { LPGLOBALVARS pgv; pgv = (LPGLOBALVARS) GetWindowLong( hwnd, DWL_USER ); if( pgv == NULL ) { return; } /* * ditch timer */ if( pgv->pjd->bHasTimer ) { KillTimer( hwnd, TIMER_ID ); pgv->pjd->bHasTimer = FALSE; } /* * done with our variables */ #if defined( WANT_SHEETS ) DoFree( pgv ); #endif } /* cleanUpJoyDlg */ /* * enableJoyWindows - enable controls for a joystick */ static void enableJoyWindows( LPGLOBALVARS pgv, HWND hwnd, BOOL enable ) { // EnableWindow( GetDlgItem(hwnd,IDC_JOYSELECT), enable ); // EnableWindow( GetDlgItem(hwnd,IDC_JOYSELECTMSG), enable ); // EnableWindow( GetDlgItem(hwnd,IDC_JOYSTICK1_FRAME), enable ); EnableWindow( GetDlgItem(hwnd,IDC_JOYCALIBRATE), enable ); EnableWindow( GetDlgItem(hwnd,IDC_JOYTEST), enable ); } /* enableJoyWindows */ /* * enableActiveJoystick - enable dialog controls based on presence of joysticks */ static void enableActiveJoystick( LPGLOBALVARS pgv, HWND hwnd ) { BOOL allowj; HINSTANCE hinst; char str[MAX_STR]; unsigned joys; LPSTR text; /* * check what joysticks are active; if it hasn't changed, just return */ joys = getActiveFlags( pgv ); if( pgv->joyActiveFlags == joys ) { return; } pgv->joyActiveFlags = joys; /* * turn off the rudder if it is gone */ if( !(joys & HASRUDDERMAYBE) ) { pgv->joyHWCurr.dwUsageSettings &= ~JOY_US_HASRUDDER; CheckDlgButton( hwnd, IDC_JOY1HASRUDDER, FALSE ); } /* * enable the appropriate windows */ allowj = ((joys & HASJOY) != 0); enableJoyWindows( pgv, hwnd, allowj ); EnableWindow( GetDlgItem( hwnd, IDC_JOY1HASRUDDER ), allowj && (joys & HASRUDDERMAYBE) ); /* * set message for the user if there is no joystick plugged in, or if * there is no joystick driver present */ if( allowj ) { text = ""; } else { str[0] = 0; text = str; hinst = GetWindowInstance( hwnd ); if( joyGetNumDevs() ) { LoadString( hinst , IDS_JOYUNPLUGGED, str, sizeof( str ) ); } else { LoadString( hinst , IDS_JOYNOTPRESENT, str, sizeof( str ) ); } } SetWindowText( GetDlgItem( hwnd, IDC_JOYMSG ), text ); if( allowj ) { enableTestCal( hwnd, pgv->joyHWCurr.dwType ); } if( allowj ) { pgv->joyHWCurr.dwUsageSettings |= JOY_US_PRESENT; } else { pgv->joyHWCurr.dwUsageSettings &= ~JOY_US_PRESENT; } RegSaveCurrentJoyHW( pgv ); RegistryUpdated( pgv ); } /* enableActiveJoystick */ /* * getNewJoyInfo - get information from the registry about a new joystick. * If no info, default to joyHWDefault settings */ static void getNewJoyInfo( LPGLOBALVARS pgv, HWND hwnd ) { UINT index; DWORD hw_type; HKEY hkey; char str[MAX_STR]; char jcfg[MAX_STR]; DWORD regtype; JOYREGHWCONFIG config; DWORD cb; BOOL same; int rc; GETKEYNAME( pgv, jcfg, REGSTR_VAL_JOYNCONFIG ); /* * get the hardware type */ index = SendDlgItemMessage( hwnd, IDC_JOYSELECT, CB_GETCURSEL, 0, 0L ); hw_type = SendDlgItemMessage( hwnd,IDC_JOYSELECT,CB_GETITEMDATA,index,0L ); same = (hw_type == pgv->joyHWCurr.dwType); /* * read the info from the registry if a new hardware type selected */ if( !same ) { pgv->joyHWCurr = pgv->pjd->joyHWDefaults[ hw_type ]; createSettingsKeyFromCurr( pgv, str ); if( !RegOpenKey( HKEY_LOCAL_MACHINE, str, &hkey ) ) { cb = sizeof( pgv->joyHWCurr ); if( !RegQueryValueEx( hkey, jcfg, NULL, ®type, (CONST LPBYTE)&config, &cb) ) { if( regtype == REG_BINARY && cb == sizeof( config ) ) { pgv->joyHWCurr.hws = config.hws; pgv->joyHWCurr.hwv = config.hwv; pgv->joyHWCurr.dwUsageSettings = config.dwUsageSettings; } } RegCloseKey( hkey ); } /* * set up the rudder bit */ if( pgv->joyHWCurr.dwUsageSettings & JOY_US_HASRUDDER ) { CheckDlgButton( hwnd, IDC_JOY1HASRUDDER, TRUE ); } else { if( IsDlgButtonChecked( hwnd, IDC_JOY1HASRUDDER ) ) { pgv->joyHWCurr.dwUsageSettings |= JOY_US_HASRUDDER; } else { pgv->joyHWCurr.dwUsageSettings &= ~JOY_US_HASRUDDER; } } } /* * disable test/calibrate buttons based on hardware picked */ enableTestCal( hwnd, hw_type ); /* * if custom selected, go get the data from the user */ if( hw_type == JOY_HW_CUSTOM ) { rc = DialogBoxParam((HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE), MAKEINTRESOURCE(IDD_JOYCUSTOM), hwnd, CustomProc, (LONG) pgv ); if( rc ) { LPCUSTVARS pcv; pcv = (LPCUSTVARS) rc; pgv->joyHWCurr.dwUsageSettings |= JOY_US_PRESENT; pgv->joyHWCurr.hws.dwFlags &= ~(JOY_HWS_HASR|JOY_HWS_HASZ| JOY_HWS_HASU| JOY_HWS_HASV| JOY_HWS_HASPOV|JOY_HWS_ISYOKE| JOY_HWS_ISGAMEPAD| JOY_HWS_ISCARCTRL| JOY_HWS_POVISPOLL| JOY_HWS_POVISBUTTONCOMBOS ); /* * NOTE: for a custom joystick, we always assume that Z is * implemented on J2 Y. */ if( pcv->bHasZ ) { pgv->joyHWCurr.hws.dwFlags |= JOY_HWS_HASZ; } /* * NOTE: for a custom joystick, we always assume that R is * implemented on J2 X. */ if( pcv->bHasR ) { pgv->joyHWCurr.hws.dwFlags |= JOY_HWS_HASR; } if( pcv->bHasPOV ) { pgv->joyHWCurr.hws.dwFlags |= JOY_HWS_HASPOV; } if( pcv->bIsYoke ) { pgv->joyHWCurr.hws.dwFlags |= JOY_HWS_ISYOKE; } if( pcv->bIsGamePad ) { pgv->joyHWCurr.hws.dwFlags |= JOY_HWS_ISGAMEPAD; } if( pcv->bIsCarCtrl ) { pgv->joyHWCurr.hws.dwFlags |= JOY_HWS_ISCARCTRL; } if( pcv->bHas2Buttons ) { pgv->joyHWCurr.hws.dwNumButtons = 2; } else { pgv->joyHWCurr.hws.dwNumButtons = 4; } DoFree( pcv ); same = FALSE; } } /* * update the registry with the new current joystick */ if( !same ) { RegSaveCurrentJoyHW( pgv ); RegistryUpdated( pgv ); PropSheet_Changed( GetParent(hwnd), hwnd ); pgv->joyActiveFlags = (unsigned) -1; enableActiveJoystick( pgv, hwnd ); } } /* getNewJoyInfo */ /* * initCurrentHW - set up the current hardware for the first time */ static void initCurrentHW( LPGLOBALVARS pgv ) { regGetCurrHW( pgv ); pgv->joyActiveFlags = (unsigned) -1; saveHWSettings( pgv ); } /* initCurrentHW */ /* * newJoyId - set up for a new joystick id */ static LPGLOBALVARS newJoyId( LPGLOBALVARS pgv, HWND hwnd, int joyid ) { UINT index; UINT indexMax; if( joyid == pgv->iJoyId ) { return pgv; } #if !defined( WANT_SHEETS ) pgv = &pgv->pjd->pgvlist[ joyid ]; #endif pgv->iJoyId = joyid; /* * save the pointer to the variables */ SetWindowLong( hwnd, DWL_USER, (LONG) pgv ); #if defined( WANT_SHEETS ) /* * set up current joystick hardware */ initCurrentHW( pgv ); #endif /* * set up windows */ pgv->joyActiveFlags = (unsigned) -1; enableActiveJoystick( pgv, hwnd ); if( pgv->joyHWCurr.dwUsageSettings & JOY_US_HASRUDDER ) { CheckDlgButton( hwnd, IDC_JOY1HASRUDDER, TRUE ); } else { CheckDlgButton( hwnd, IDC_JOY1HASRUDDER, FALSE ); } /* * select the current info */ indexMax = SendDlgItemMessage( hwnd, IDC_JOYSELECT, CB_GETCOUNT, 0, 0 ); for (index = 0; index < indexMax; index++) { DWORD type; type = SendDlgItemMessage( hwnd, IDC_JOYSELECT, CB_GETITEMDATA, index, 0 ); if (type == pgv->joyHWCurr.dwType) break; } if (index == indexMax) index = 1; // custom SendDlgItemMessage( hwnd, IDC_JOYSELECT, CB_SETCURSEL, index, 0L ); #if !defined( WANT_SHEETS ) SendDlgItemMessage( hwnd, IDC_JOYCURRENTID, CB_SETCURSEL, pgv->iJoyId, 0L ); #endif return pgv; } /* newJoyId */ /* * showResetInfo */ static void showResetInfo( HWND hwnd, BOOL show ) { EnableWindow( GetDlgItem( hwnd, IDC_JOYTROUBLESHOOT_FRAME ), show ); EnableWindow( GetDlgItem( hwnd, IDC_JOYTROUBLESHOOT_TEXT ), show ); EnableWindow( GetDlgItem( hwnd, IDC_JOYRESET ), show ); } /* showResetInfo */ /* * doJoyDlgInitDialog - process initialization for joystick tabbed dialog */ static BOOL doJoyDlgInitDialog( HWND hwnd, LPARAM lParam ) { HINSTANCE hinst; LPPROPSHEETPAGE ppsp; int i; char str[MAX_STR]; LPGLOBALVARS pgv; LPJOYDATA pjd; LPJOYDATAPTR pjdp; HKEY hkey; /* * pointer to data */ ppsp = (LPPROPSHEETPAGE) lParam; pjdp = (LPJOYDATAPTR) ppsp->lParam; pjd = pjdp->pjd; /* * create global variables. These will be used by all dialogs */ #if defined( WANT_SHEETS ) pgv = DoAlloc( sizeof( GLOBALVARS ) ); if( pgv == NULL ) { return FALSE; } /* * get joystick id that this sheet is for */ pgv->iJoyId = pjdp->iJoyId; pgv->pjd = pjd; DPF( "Tab for joystick %d started\r\n", pgv->iJoyId ); #else pgv = &pjd->pgvlist[ pjdp->iJoyId ]; #endif /* * get device caps */ getDevCaps( pgv ); /* * how many predefined joystick types should we display? */ pgv->cJoystickTypes = 2; // display None and Custom only if( !RegOpenKey( HKEY_LOCAL_MACHINE, REGSTR_PATH_JOYSTICK, &hkey ) ) { DWORD type; DWORD val = 0; DWORD cb = sizeof(val); if( !RegQueryValueEx( hkey, REGSTR_VAL_JOYTYPES, NULL, &type, (CONST LPBYTE)&val, &cb) ) { pgv->cJoystickTypes += val; } RegCloseKey( hkey ); } pgv->cJoystickTypes = max( pgv->cJoystickTypes, 2 ); // Must have none/cust pgv->cJoystickTypes = min( pgv->cJoystickTypes, 12 ); /* * callback timer for checking if joysticks are plugged/unplugged */ if( !pjd->bHasTimer ) { pjd->bHasTimer = SetTimer( hwnd, TIMER_ID, JOYCHECKTIME, NULL ); pjd->bUseTimer = TRUE; } /* * set up pre-defined joystick list */ hinst = GetWindowInstance( hwnd ); for( i=IDS_JOYHW0; i<(IDS_JOYHW0 + pgv->cJoystickTypes); i++ ) { if( LoadString( hinst , i, str, sizeof( str ) ) ) { UINT dwItem; dwItem = SendDlgItemMessage( hwnd, IDC_JOYSELECT, CB_ADDSTRING, 0, (LONG) (LPSTR) str ); SendDlgItemMessage( hwnd, IDC_JOYSELECT, CB_SETITEMDATA, dwItem, i -IDS_JOYHW0 + JOY_HW_NONE ); } } /* * set up OEM joystick list */ for( i=0;ioemCount;i++ ) { UINT dwItem; dwItem = SendDlgItemMessage( hwnd, IDC_JOYSELECT, CB_ADDSTRING, 0, (LONG) (LPSTR) pjd->oemList[i].ident_string ); SendDlgItemMessage( hwnd, IDC_JOYSELECT, CB_SETITEMDATA, dwItem, i +JOY_HW_LASTENTRY); } /* * set up joystick choices list */ #if !defined(WANT_SHEETS) { int numdevs; char strid[MAX_STR]; if( LoadString( hinst, IDS_JOY, str, sizeof( str ) ) ) { numdevs = joyGetNumDevs(); for( i=0;iiJoyId = -1; newJoyId( pgv, hwnd, pjdp->iJoyId ); /* * enable/disable our Reset button */ showResetInfo( hwnd, pjd->bHasNonStandardUserVals ); return TRUE; } /* doJoyDlgInitDialog */ /* * doJoyDlgCommand - process WM_COMMAND message for main joystick tabbed dialog */ static void doJoyDlgCommand( HWND hwnd, int id, HWND hctl, UINT code ) { LPGLOBALVARS pgv; pgv = (LPGLOBALVARS) GetWindowLong( hwnd, DWL_USER ); switch( id ) { /* * new joystick has been picked */ case IDC_JOYSELECT: if( code == CBN_SELCHANGE ) { getNewJoyInfo( pgv, hwnd ); } break; #if !defined( WANT_SHEET ) /* * new joystick id has been picked */ case IDC_JOYCURRENTID: if( code == CBN_SELCHANGE ) { int joyid; joyid = SendDlgItemMessage( hwnd, IDC_JOYCURRENTID, CB_GETCURSEL, 0, 0L ); pgv = newJoyId( pgv, hwnd, joyid ); regSetUserVals( pgv->pjd, TRUE ); RegSaveCurrentJoyHW( pgv ); RegistryUpdated( pgv ); } break; #endif /* * calibrate current joystick */ case IDC_JOYCALIBRATE: pgv->pjd->bUseTimer = FALSE; DoCalibrate( pgv, hwnd ); pgv->pjd->bUseTimer = TRUE; break; /* * test either joystick 1 or joystick 2 */ case IDC_JOYTEST: pgv->pjd->bUseTimer = FALSE; DoTest( pgv, hwnd, NULL, pgv ); pgv->pjd->bUseTimer = TRUE; break; /* * reset to user values */ case IDC_JOYRESET: pgv->pjd->bResetUserVals = TRUE; PropSheet_Changed( GetParent(hwnd), hwnd ); break; /* * rudder selected/unselected */ case IDC_JOY1HASRUDDER: { LPJOYREGHWCONFIG pcfg; /* * rudder status changed, force recalibration (leave POV alone if * it was button based) */ pcfg = &pgv->joyHWCurr; if( (pcfg->hws.dwFlags & JOY_HWS_HASPOV) && (pcfg->hws.dwFlags & JOY_HWS_POVISBUTTONCOMBOS) ) { pcfg->hwv.dwCalFlags &= JOY_ISCAL_POV; } else { pcfg->hwv.dwCalFlags = 0; } if( IsDlgButtonChecked( hwnd, id ) ) { pcfg->dwUsageSettings |= JOY_US_HASRUDDER; } else { pcfg->dwUsageSettings &= ~JOY_US_HASRUDDER; } pgv->joyActiveFlags = (unsigned) -1; enableActiveJoystick( pgv, hwnd ); PropSheet_Changed( GetParent(hwnd), hwnd ); break; } case ID_APPLY: { DPF( "ID_APPLY\r\n" ); #if !defined( WANT_SHEETS ) { int i; int numjoys; numjoys = joyGetNumDevs(); for( i=0;ipjd->pgvlist[i] ); saveHWSettings( &pgv->pjd->pgvlist[i] ); } } #else regPermSaveAllInfo( pgv ); saveHWSettings( pgv ); #endif if( pgv->pjd->bResetUserVals ) { regUserValsFini( pgv->pjd ); regUserValsInit( pgv->pjd ); pgv->pjd->bResetUserVals = FALSE; } showResetInfo( hwnd, pgv->pjd->bHasNonStandardUserVals ); break; } case ID_INIT: DPF( "ID_INIT\r\n" ); /* * we've been re-activated, reset the current joystick settings */ regSetUserVals( pgv->pjd, TRUE ); RegSaveCurrentJoyHW( pgv ); RegistryUpdated( pgv ); break; case IDOK: DPF( "IDOK\r\n" ); EndDialog(hwnd, TRUE ); break; case IDCANCEL: DPF( "IDCANCEL\r\n" ); pgv->pjd->bResetUserVals = FALSE; #if !defined( WANT_SHEETS ) { int i; int numjoys; numjoys = joyGetNumDevs(); for( i=0;ipjd->pgvlist[i] ); } } #else restoreHWSettings( pgv ); #endif RegistryUpdated( pgv ); EndDialog(hwnd, FALSE ); break; default: break; } } /* doJoyDlgCommand */ /* * context help for the main dialog */ const static DWORD aJoystickHelpIDs[] = { // Context Help IDs IDC_JOYCURRENTIDMSG, IDH_JOYSTICK_CURRENT, IDC_JOYCURRENTID, IDH_JOYSTICK_CURRENT, IDC_JOYSELECTMSG, IDH_JOYSTICK_SELECT, IDC_JOYSELECT, IDH_JOYSTICK_SELECT, IDC_JOY1HASRUDDER, IDH_JOYSTICK_RUDDER, IDC_JOYCALIBRATE, IDH_JOYSTICK_CALIBRATE, IDC_JOYTEST, IDH_JOYSTICK_TEST, IDC_JOYSTICK1_FRAME, IDH_JOYSTICK_GROUPBOX, IDC_JOYMSG, NO_HELP, IDC_ICON_1, NO_HELP, IDC_ICON_2, NO_HELP, IDC_JOYTROUBLESHOOT_FRAME, IDH_JOYSTICK_RESET, IDC_JOYRESET, IDH_JOYSTICK_RESET, IDC_JOYTROUBLESHOOT_TEXT, NO_HELP, 0, 0 }; /* * JoystickDlg - dialog procedure for joystick tabbed dialog */ BOOL CALLBACK JoystickDlg( HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lParam) { BOOL rc; switch( umsg ) { case WM_INITDIALOG: rc = doJoyDlgInitDialog( hwnd, lParam ); if( !rc ) { EndDialog( hwnd, 0 ); } return FALSE; case WM_COMMAND: HANDLE_WM_COMMAND( hwnd, wParam, lParam, doJoyDlgCommand ); break; case WM_ACTIVATE: /* * we've been activated, pretend we were re-selected */ if( LOWORD( wParam ) != WA_INACTIVE ) { FORWARD_WM_COMMAND( hwnd, ID_INIT, 0, 0, SendMessage ); } break; case WM_DESTROY: cleanUpJoyDlg( hwnd ); break; case WM_TIMER: { LPGLOBALVARS pgv; pgv = (LPGLOBALVARS) GetWindowLong( hwnd, DWL_USER ); if( pgv->pjd->bUseTimer ) { pgv->pjd->bUseTimer = FALSE; enableActiveJoystick( pgv, hwnd ); pgv->pjd->bUseTimer = TRUE; } break; } case WM_HELP: WinHelp((HWND)((LPHELPINFO) lParam)->hItemHandle, cszHelpFile, HELP_WM_HELP, (DWORD)(LPSTR) aJoystickHelpIDs); return TRUE; case WM_CONTEXTMENU: WinHelp((HWND) wParam, cszHelpFile, HELP_CONTEXTMENU, (DWORD)(LPVOID) aJoystickHelpIDs); return TRUE; case WM_NOTIFY: { NMHDR FAR * lpnm = (NMHDR FAR *)lParam; switch(lpnm->code) { case PSN_KILLACTIVE: FORWARD_WM_COMMAND( hwnd, IDOK, 0, 0, SendMessage ); return TRUE; case PSN_APPLY: FORWARD_WM_COMMAND( hwnd, ID_APPLY, 0, 0, SendMessage ); return TRUE; case PSN_SETACTIVE: FORWARD_WM_COMMAND( hwnd, ID_INIT, 0, 0, SendMessage ); return TRUE; case PSN_RESET: FORWARD_WM_COMMAND( hwnd, IDCANCEL, 0, 0, SendMessage ); return TRUE; } break; } default: break; } return FALSE; } /* JoystickDlg */ /*************************************************************************** GLOBAL JOYSTICK DATA FUNCTIONS FOLLOW ***************************************************************************/ /* * default joysticks */ #define TYPE00 0 #define TYPE01 0 #define TYPE02 0 #define TYPE03 0 #define TYPE04 JOY_HWS_ISGAMEPAD #define TYPE05 JOY_HWS_ISYOKE #define TYPE06 JOY_HWS_HASZ | JOY_HWS_ISYOKE #define TYPE07 JOY_HWS_HASZ #define TYPE08 JOY_HWS_HASZ #define TYPE09 JOY_HWS_ISGAMEPAD #define TYPE10 JOY_HWS_ISYOKE #define TYPE11 JOY_HWS_HASZ | JOY_HWS_ISYOKE static JOYREGHWCONFIG _joyHWDefaults[] = { { {TYPE00,0},JOY_US_PRESENT,{{0,0,0,0,0,0,0,0,0},{0,0,0,0}},JOY_HW_NONE}, { {TYPE01,2},JOY_US_PRESENT,{{0,0,0,0,0,0,0,0,0},{0,0,0,0}},JOY_HW_CUSTOM}, { {TYPE02,2},JOY_US_PRESENT,{{0,0,0,0,0,0,0,0,0},{0,0,0,0}},JOY_HW_2A_2B_GENERIC}, { {TYPE03,4},JOY_US_PRESENT,{{0,0,0,0,0,0,0,0,0},{0,0,0,0}},JOY_HW_2A_4B_GENERIC}, { {TYPE04,2},JOY_US_PRESENT,{{0,0,0,0,0,0,0,0,0},{0,0,0,0}},JOY_HW_2B_GAMEPAD}, { {TYPE05,2},JOY_US_PRESENT,{{0,0,0,0,0,0,0,0,0},{0,0,0,0}},JOY_HW_2B_FLIGHTYOKE}, { {TYPE06,2},JOY_US_PRESENT,{{0,0,0,0,0,0,0,0,0},{0,0,0,0}},JOY_HW_2B_FLIGHTYOKETHROTTLE}, { {TYPE07,2},JOY_US_PRESENT,{{0,0,0,0,0,0,0,0,0},{0,0,0,0}},JOY_HW_3A_2B_GENERIC}, { {TYPE08,4},JOY_US_PRESENT,{{0,0,0,0,0,0,0,0,0},{0,0,0,0}},JOY_HW_3A_4B_GENERIC}, { {TYPE09,4},JOY_US_PRESENT,{{0,0,0,0,0,0,0,0,0},{0,0,0,0}},JOY_HW_4B_GAMEPAD}, { {TYPE10,4},JOY_US_PRESENT,{{0,0,0,0,0,0,0,0,0},{0,0,0,0}},JOY_HW_4B_FLIGHTYOKE}, { {TYPE11,4},JOY_US_PRESENT,{{0,0,0,0,0,0,0,0,0},{0,0,0,0}},JOY_HW_4B_FLIGHTYOKETHROTTLE}, }; /* * registry strings for calibration messages */ static LPSTR _oemCalRegStrs[] = { REGSTR_VAL_JOYOEMCAL1, REGSTR_VAL_JOYOEMCAL2, REGSTR_VAL_JOYOEMCAL3, REGSTR_VAL_JOYOEMCAL4, REGSTR_VAL_JOYOEMCAL5, REGSTR_VAL_JOYOEMCAL6, REGSTR_VAL_JOYOEMCAL7, REGSTR_VAL_JOYOEMCAL8, REGSTR_VAL_JOYOEMCAL9, REGSTR_VAL_JOYOEMCAL10, REGSTR_VAL_JOYOEMCAL11, REGSTR_VAL_JOYOEMCAL12, }; /* * base registry keys */ static char szCfgKey[] = REGSTR_PATH_JOYCONFIG; static char szCurrCfgKey[] = REGSTR_KEY_JOYCURR; static char szSettingsCfgKey[] = REGSTR_KEY_JOYSETTINGS; /* * freeOEMListItem - free a list of oem data */ static void freeOEMListItem( LPJOYDATA pjd, int i ) { int j; DoFree( pjd->oemList[i].keyname ); DoFree( pjd->oemList[i].ident_string ); DoFree( pjd->oemList[i].vxd_name ); DoFree( pjd->oemList[i].xy_label ); DoFree( pjd->oemList[i].z_label ); DoFree( pjd->oemList[i].r_label ); DoFree( pjd->oemList[i].u_label ); DoFree( pjd->oemList[i].v_label ); DoFree( pjd->oemList[i].pov_label ); DoFree( pjd->oemList[i].testmove_desc ); DoFree( pjd->oemList[i].testbutton_desc ); DoFree( pjd->oemList[i].testmove_cap ); DoFree( pjd->oemList[i].testbutton_cap ); DoFree( pjd->oemList[i].testwin_cap ); DoFree( pjd->oemList[i].cal_cap ); DoFree( pjd->oemList[i].calwin_cap ); for( j=0;joemList[i].cal_strs[j] ); } } /* freeOEMListItem */ /* * initHWDefaults - initialize the hardware list: use defaults + OEM types * defined in the registry */ static void initHWDefaults( LPJOYDATA pjd ) { int list_size; int def_size; DWORD isubkey; DWORD keyidx; HKEY hkey; HKEY hsubkey; char str[MAX_STR]; DWORD clsize; DWORD num_subkeys; DWORD dont_care; DWORD longest_key; FILETIME ftime; LPSTR keyname; JOYREGHWSETTINGS hws; DWORD longest_val; DWORD type; DWORD cb; int i; int j; int ctype; LPSTR tmpstr; int fail; def_size = sizeof( _joyHWDefaults )/sizeof( _joyHWDefaults[0] ); list_size = def_size; pjd->oemCount = 0; if( !RegOpenKey( HKEY_LOCAL_MACHINE, REGSTR_PATH_JOYOEM, &hkey ) ) { clsize = sizeof( str ); if( !RegQueryInfoKey ( hkey, str, &clsize, NULL, &num_subkeys, &longest_key, &dont_care, &dont_care, &dont_care, &dont_care, // address of buffer for longest value data length &dont_care, &ftime ) ) { pjd->oemList = DoAlloc( num_subkeys * sizeof( OEMLIST )); if( pjd->oemList != NULL ) { pjd->oemCount = num_subkeys; list_size += num_subkeys; } longest_key++; } } pjd->joyHWDefaults = DoAlloc( list_size * sizeof( JOYREGHWCONFIG ) ); if( pjd->joyHWDefaults == NULL ) { pjd->joyHWDefaults = _joyHWDefaults; } else { memcpy( pjd->joyHWDefaults, _joyHWDefaults, def_size * sizeof( JOYREGHWCONFIG ) ); /* * if we have keys in the registry, go fetch them */ if( list_size > def_size ) { isubkey = 0; keyidx = 0; keyname = DoAlloc( longest_key ); if( keyname == NULL ) { keyname = str; longest_key = sizeof( str ); } /* * run through all keys, getting the info on them */ while( !RegEnumKey( hkey, keyidx, keyname, longest_key ) ) { if( !RegOpenKey( hkey, keyname, &hsubkey ) ) { if( !RegQueryInfoKey ( hsubkey, str, &clsize, NULL, &dont_care, &dont_care, &dont_care, &dont_care, &dont_care, &longest_val, &dont_care, &ftime ) ) { pjd->oemList[isubkey].keyname = DoAlloc( strlen( keyname ) +1 ); tmpstr = DoAlloc( longest_val+1 ); if( pjd->oemList[isubkey].keyname != NULL && tmpstr != NULL ) { strcpy( pjd->oemList[isubkey].keyname, keyname ); cb = sizeof( hws ); if( !RegQueryValueEx( hsubkey, REGSTR_VAL_JOYOEMDATA, NULL, &type, (CONST LPBYTE)&hws, &cb) ) { if( type == REG_BINARY && cb == sizeof( hws ) ) { pjd->oemList[isubkey].hws = hws; } } fail = 0; fail |= regGetOEMStr( hsubkey, REGSTR_VAL_JOYOEMCALLOUT, tmpstr, longest_val, &pjd->oemList[isubkey].vxd_name ); fail |= regGetOEMStr( hsubkey, REGSTR_VAL_JOYOEMNAME, tmpstr, longest_val, &pjd->oemList[isubkey].ident_string ); for( j=0;joemList[isubkey].cal_strs[j] ); } fail |= regGetOEMStr( hsubkey, REGSTR_VAL_JOYOEMXYLABEL, tmpstr, longest_val, &pjd->oemList[isubkey].xy_label ); fail |= regGetOEMStr( hsubkey, REGSTR_VAL_JOYOEMZLABEL, tmpstr, longest_val, &pjd->oemList[isubkey].z_label ); fail |= regGetOEMStr( hsubkey, REGSTR_VAL_JOYOEMRLABEL, tmpstr, longest_val, &pjd->oemList[isubkey].r_label ); fail |= regGetOEMStr( hsubkey, REGSTR_VAL_JOYOEMULABEL, tmpstr, longest_val, &pjd->oemList[isubkey].u_label ); fail |= regGetOEMStr( hsubkey, REGSTR_VAL_JOYOEMVLABEL, tmpstr, longest_val, &pjd->oemList[isubkey].v_label ); fail |= regGetOEMStr( hsubkey, REGSTR_VAL_JOYOEMPOVLABEL, tmpstr, longest_val, &pjd->oemList[isubkey].pov_label ); fail |= regGetOEMStr( hsubkey, REGSTR_VAL_JOYOEMTESTMOVEDESC, tmpstr, longest_val, &pjd->oemList[isubkey].testmove_desc ); fail |= regGetOEMStr( hsubkey, REGSTR_VAL_JOYOEMTESTBUTTONDESC, tmpstr, longest_val, &pjd->oemList[isubkey].testbutton_desc ); fail |= regGetOEMStr( hsubkey, REGSTR_VAL_JOYOEMTESTMOVECAP, tmpstr, longest_val, &pjd->oemList[isubkey].testmove_cap ); fail |= regGetOEMStr( hsubkey, REGSTR_VAL_JOYOEMTESTBUTTONCAP, tmpstr, longest_val, &pjd->oemList[isubkey].testbutton_cap ); fail |= regGetOEMStr( hsubkey, REGSTR_VAL_JOYOEMTESTWINCAP, tmpstr, longest_val, &pjd->oemList[isubkey].testwin_cap ); fail |= regGetOEMStr( hsubkey, REGSTR_VAL_JOYOEMCALCAP, tmpstr, longest_val, &pjd->oemList[isubkey].cal_cap ); fail |= regGetOEMStr( hsubkey, REGSTR_VAL_JOYOEMCALWINCAP, tmpstr, longest_val, &pjd->oemList[isubkey].calwin_cap ); if( fail ) { freeOEMListItem( pjd, isubkey ); } else { isubkey++; } } else { DoFree( pjd->oemList[isubkey].keyname ); } DoFree( tmpstr ); RegCloseKey( hsubkey ); } } keyidx++; } pjd->oemCount = isubkey; /* * sort the list, and then fill in the joyHWDefault array */ if( pjd->oemCount > 0 ) { for( i=0;ioemCount;i++ ) { for( j=i;joemCount;j++ ) { OEMLIST ol; if( strcmp( pjd->oemList[i].ident_string, pjd->oemList[j].ident_string ) > 0 ) { ol = pjd->oemList[i]; pjd->oemList[i] = pjd->oemList[j]; pjd->oemList[j] = ol; } } } for( i=0;ioemCount;i++ ) { ctype = i+JOY_HW_LASTENTRY; memset( &pjd->joyHWDefaults[ctype], 0, sizeof( pjd->joyHWDefaults[ctype] ) ); pjd->joyHWDefaults[ctype].hws = pjd->oemList[i].hws; pjd->joyHWDefaults[ctype].dwUsageSettings = JOY_US_ISOEM|JOY_US_PRESENT; pjd->joyHWDefaults[ctype].dwType = ctype; } } if( keyname != str ) { DoFree( keyname ); } } } } /* initHWDefaults */ /* * finiHWList - finished with the hardware list, free it */ static void finiHWList( LPJOYDATA pjd ) { int i; if( pjd->joyHWDefaults != NULL ) { if( pjd->joyHWDefaults != _joyHWDefaults ) { DoFree( pjd->joyHWDefaults ); } pjd->joyHWDefaults = NULL; } if( pjd->oemList != NULL ) { for( i=0;ioemCount;i++ ) { freeOEMListItem( pjd, i ); } DoFree( pjd->oemList ); pjd->oemList = NULL; pjd->oemCount = 0; } } /* finiHWList */ /* * getRegKeys - get the registry keys we need */ static void getRegKeys( LPJOYDATA pjd ) { int len; JOYCAPS jc; if (joyGetDevCaps (0, &jc, sizeof(jc)) != JOYERR_NOERROR) lstrcpy (jc.szRegKey, TEXT("joystick.dll<0000>")); /* * set up registry keys */ pjd->regCfgKey = NULL; pjd->regCurrCfgKey = NULL; pjd->regSettingsCfgKey = NULL; len = sizeof( szCfgKey ); pjd->regCfgKey = DoAlloc( len ); if( pjd->regCfgKey != NULL ) { strcpy( pjd->regCfgKey, szCfgKey ); pjd->regCurrCfgKey = DoAlloc( len +1 +1 +lstrlen(jc.szRegKey) +sizeof( szCurrCfgKey ) ); if( pjd->regCurrCfgKey != NULL ) { strcpy( pjd->regCurrCfgKey, pjd->regCfgKey ); strcat( pjd->regCurrCfgKey, "\\" ); strcat( pjd->regCurrCfgKey, jc.szRegKey ); strcat( pjd->regCurrCfgKey, "\\" ); strcat( pjd->regCurrCfgKey, szCurrCfgKey ); } pjd->regSettingsCfgKey = DoAlloc( len +1 +1 +lstrlen(jc.szRegKey) +sizeof( szSettingsCfgKey ) ); if( pjd->regSettingsCfgKey != NULL ) { strcpy( pjd->regSettingsCfgKey, pjd->regCfgKey ); strcat( pjd->regSettingsCfgKey, "\\" ); strcat( pjd->regSettingsCfgKey, jc.szRegKey ); strcat( pjd->regSettingsCfgKey, "\\" ); strcat( pjd->regSettingsCfgKey, szSettingsCfgKey ); } } } /* getRegKeys */ /* * JoystickDataInit */ LPJOYDATA JoystickDataInit( void ) { LPJOYDATA pjd; pjd = DoAlloc( sizeof( JOYDATA ) ); if( pjd == NULL ) { return NULL; } /* * go set up all our defaults + oem lists */ initHWDefaults( pjd ); /* * get registry keys used by everyone */ getRegKeys( pjd ); /* * brushes for use by button display and bar display (z & r info) */ pjd->hbUp = CreateSolidBrush( ACTIVE_COLOR ); pjd->hbDown = CreateSolidBrush( INACTIVE_COLOR ); /* * set up user values we like */ regUserValsInit( pjd ); #if !defined( WANT_SHEETS ) { /* * set up array of "global" vars (global to a joystick id) */ int numjoys; int i; numjoys = joyGetNumDevs(); if( numjoys == 0 ) { return NULL; } pjd->pgvlist = DoAlloc( sizeof( GLOBALVARS ) * numjoys ); if( pjd->pgvlist == NULL ) { return NULL; } for( i=0;ipgvlist[i].iJoyId = i; pjd->pgvlist[i].pjd = pjd; initCurrentHW( &pjd->pgvlist[i] ); } } #endif return pjd; } /* JoystickDataInit */ /* * JoystickDataFini - finished with DLL wide joystick data data */ void JoystickDataFini( LPJOYDATA pjd ) { /* * ditch brushes */ if( pjd->hbUp != NULL ) { DeleteObject( pjd->hbUp ); } if( pjd->hbDown != NULL ) { DeleteObject( pjd->hbDown ); } /* * done with hardware list */ finiHWList( pjd ); /* * restore user values in registry */ regUserValsFini( pjd ); /* * done with registry keys */ DoFree( pjd->regCfgKey ); DoFree( pjd->regCurrCfgKey ); DoFree( pjd->regSettingsCfgKey ); #if !defined( WANT_SHEETS ) DoFree( pjd->pgvlist ); #endif /* * free up the joystick data */ DoFree( pjd ); #ifdef DEBUG if( allocCount != 0 ) { MBOX( "Memory left unfreed: %d allocations", allocCount ); } #endif } /* JoystickDataFini */