/***************************************************************************** * * DIHid.c * * Copyright (c) 1996 Microsoft Corporation. All Rights Reserved. * * Abstract: * * WINNT implementation of JOYHID. * * Contents: * * DIWdm_JoyHidMapping * JoyReg_JoyIdToDeviceInterface * *****************************************************************************/ #include "dinputpr.h" #undef sqfl #define sqfl sqflWDM #include "dijoyhid.h" /***************************************************************************** * * @doc INTERNAL * * @func HRESULT EXTERNAL | DIWdm_JoyHidMapping | * * Does the work done by JoyHid on Win9x. This function * maps the Joystick ID to a HID device and talks to the * HID device to obtain its capabilities. * * @parm IN int | idJoy | * * The Id of the joystick to be located. * * @parm OUT PVXDINITPARAMS | pvip | OPTIONAL * Address of a VXDINITPARAMS structure that is filled out * by this function. This is an optional parameter * and can be NULL * * @parm OUT LPDIJOYCONFIG | pcfg | * Address of a DIJOYCONFIG structure that is filled out * by this function. This is an optional parameter. * * @parm IN OUT LPDIJOYTYPEINFO | pdijti | * Address of a DIJOYTYPEINFO structure that is filled out * by this function. This is an optional parameter. * If passed in, the hws.dwFlags is used to initialize the * same flags in the DIJOYCONFIG structure. * * @returns HRESULT * Returns a COM error code * *****************************************************************************/ /* * ISSUE-2001/03/29-timgill function uses too much stack space * This function uses over 4K of stack space! * This causes the Win9x build to choke looking for _chkstk. * Hack by forcing caller to pass pcfg and pdijti */ HRESULT EXTERNAL DIWdm_JoyHidMapping ( IN int idJoy, OUT PVXDINITPARMS pvip, OPTIONAL OUT LPDIJOYCONFIG pcfg, OPTIONAL IN OUT LPDIJOYTYPEINFO pdijti ) { HRESULT hres; PHIDDEVICEINFO phdi; VXDINITPARMS vip; // DIJOYCONFIG cfg; // DIJOYTYPEINFO dijti; DWORD wCaps = 0; DIPROPINFO propi; DIPROPSTRING dips; DIPROPDWORD dipd; BOOL fBadCalData = FALSE; EnterProc(DIWdm_JoyHidMapping, (_ "uxx", idJoy, pvip, pcfg)); // AssertF(InCrit()); if( pvip == NULL ) { ZeroX(vip); vip.dwSize = cbX(vip); pvip = &vip; } // AssertF(pcfg != NULL ); // if( pcfg == NULL ) // { // ZeroX(cfg); // cfg.dwSize = cbX(cfg); // pcfg = & cfg; // } AssertF(pdijti != NULL ); // if(pdijti == NULL ) // { // ZeroX(dijti); // dijti.dwSize = cbX(dijti); // pdijti = &dijti; // } /* * Copy the type info because JOY_HWS_ISYOKE, JOY_HWS_ISCARCTRL and * JOY_HWS_ISHEADTRACKER have no simple equivalents in HID so would * otherwise get lost. No harm done if it's zero. * Note, the dwFlags is built in pvip then copied elsewhere. */ pvip->dwFlags = pdijti->hws.dwFlags; phdi = phdiFindJoyId(idJoy); if( phdi != NULL ) { IDirectInputDeviceCallback *pdcb; hres = CHid_New(0, &phdi->guid, &IID_IDirectInputDeviceCallback, (PPV)&pdcb); if( SUCCEEDED(hres) ) { DIDEVCAPS dc; hres = pdcb->lpVtbl->GetCapabilities(pdcb, &dc ); if( SUCCEEDED(hres) ) { DIDEVICEINSTANCEW didi; didi.dwSize = cbX(didi); hres = pdcb->lpVtbl->GetDeviceInfo(pdcb, &didi); if( SUCCEEDED(hres) ) { LPDIDATAFORMAT pdf; hres = pdcb->lpVtbl->GetDataFormat(pdcb, &pdf); if( SUCCEEDED(hres) ) { DIPROPCAL dipc; DWORD axis, pov = 0; ZeroBuf(pvip->Usages, 6 * cbX(pvip->Usages[0])); hres = pdcb->lpVtbl->MapUsage(pdcb, CheckHatswitch->dwUsage, &propi.iobj); if(SUCCEEDED(hres) ) { pvip->dwPOV1usage = CheckHatswitch->dwUsage; pvip->dwFlags |= CheckHatswitch->dwFlags; wCaps |= CheckHatswitch->dwCaps; propi.pguid = DIPROP_GRANULARITY; propi.dwDevType = pdf->rgodf[propi.iobj].dwType; hres = pdcb->lpVtbl->GetProperty(pdcb, &propi, &dipd.diph); if( SUCCEEDED( hres ) ) { if( dipd.dwData >= 9000 ) // 4 directional POV { wCaps |= JOYCAPS_POV4DIR; if( pcfg != NULL ) { pcfg->hwc.hwv.dwPOVValues[JOY_POVVAL_FORWARD] = JOY_POVFORWARD; pcfg->hwc.hwv.dwPOVValues[JOY_POVVAL_BACKWARD] = JOY_POVBACKWARD; pcfg->hwc.hwv.dwPOVValues[JOY_POVVAL_LEFT] = JOY_POVLEFT; pcfg->hwc.hwv.dwPOVValues[JOY_POVVAL_RIGHT] = JOY_POVRIGHT; } } else // Continuous POV { wCaps |= JOYCAPS_POVCTS; } } } for( axis = 0; axis < cA(AxesUsages)-1; axis++ ) { USAGES *pUse = &AxesUsages[axis]; DWORD dwCurAxisPos = pUse->dwAxisPos; if( pvip->Usages[dwCurAxisPos] != 0) { continue; } else { int i; BOOL bHasUsed = FALSE; for( i = 0; i < (int)dwCurAxisPos; i++ ) { if( pvip->Usages[i] == pUse->dwUsage ) { bHasUsed = TRUE; break; } } if( bHasUsed ) { continue; } } hres = pdcb->lpVtbl->MapUsage(pdcb, pUse->dwUsage, &propi.iobj); if(SUCCEEDED(hres) ) { pvip->Usages[dwCurAxisPos] = pUse->dwUsage; pvip->dwFlags |= pUse->dwFlags; wCaps |= pUse->dwCaps; propi.pguid = DIPROP_CALIBRATION; propi.dwDevType = pdf->rgodf[propi.iobj].dwType; hres = pdcb->lpVtbl->GetProperty(pdcb, &propi, &dipc.diph); if( SUCCEEDED(hres) && pcfg != NULL ) { #ifdef WINNT (&pcfg->hwc.hwv.jrvHardware.jpMin.dwX)[dwCurAxisPos] = dipc.lMin; (&pcfg->hwc.hwv.jrvHardware.jpMax.dwX)[dwCurAxisPos] = dipc.lMax; (&pcfg->hwc.hwv.jrvHardware.jpCenter.dwX)[dwCurAxisPos] = CCal_Midpoint(dipc.lMin, dipc.lMax); #else DIPROPRANGE diprp; DIPROPRANGE diprl; propi.pguid = DIPROP_PHYSICALRANGE; propi.dwDevType = pdf->rgodf[propi.iobj].dwType; hres = pdcb->lpVtbl->GetProperty(pdcb, &propi, &diprp.diph); if( SUCCEEDED( hres ) ) { propi.pguid = DIPROP_LOGICALRANGE; propi.dwDevType = pdf->rgodf[propi.iobj].dwType; hres = pdcb->lpVtbl->GetProperty(pdcb, &propi, &diprl.diph); if( SUCCEEDED( hres ) ) { LONG lMin, lMax; lMin = (&pcfg->hwc.hwv.jrvHardware.jpMin.dwX)[dwCurAxisPos] = CHid_CoordinateTransform( (PLMINMAX)&diprp.lMin, (PLMINMAX)&diprl.lMin, dipc.lMin ); lMax = (&pcfg->hwc.hwv.jrvHardware.jpMax.dwX)[dwCurAxisPos] = CHid_CoordinateTransform( (PLMINMAX)&diprp.lMin, (PLMINMAX)&diprl.lMin, dipc.lMax ); (&pcfg->hwc.hwv.jrvHardware.jpCenter.dwX)[dwCurAxisPos] = CCal_Midpoint(lMin, lMax); if( lMin >= lMax ) { fBadCalData = TRUE; break; } } } #endif } } } //for (axis=0... } //GetDataFormat pvip->hres = S_OK; pvip->dwSize = cbX(*pvip); /* Which version of VJOYD are we? */ pvip->dwFlags |= JOY_HWS_AUTOLOAD; /* Describes the device */ if(didi.wUsage == HID_USAGE_GENERIC_GAMEPAD ) pvip->dwFlags |= JOY_HWS_ISGAMEPAD ; pvip->dwId = idJoy; /* Internal joystick ID */ pvip->dwFirmwareRevision = dc.dwFirmwareRevision; pvip->dwHardwareRevision = dc.dwHardwareRevision; pvip->dwFFDriverVersion = dc.dwFFDriverVersion; pvip->dwFilenameLengths = lstrlen(phdi->pdidd->DevicePath); pvip->pFilenameBuffer = phdi->pdidd->DevicePath; //pvip->Usages[6]; //pvip->dwPOV1usage = 0x0; pvip->dwPOV2usage = 0x0; pvip->dwPOV3usage = 0x0; /* Fill all fields of cfg */ if( pcfg != NULL ) { AssertF(pcfg->dwSize == cbX(*pcfg) ); pcfg->guidInstance = phdi->guid; pcfg->hwc.hws.dwNumButtons = dc.dwButtons; pcfg->hwc.hws.dwFlags = pvip->dwFlags; //pcfg.hwc.hwv.jrvHardware //pcfg.hwc.hwv.dwPOVValues pcfg->hwc.hwv.dwCalFlags = 0x0; if( ( LOWORD(phdi->guidProduct.Data1) == MSFT_SYSTEM_VID ) &&( ( HIWORD(phdi->guidProduct.Data1) >= MSFT_SYSTEM_PID + JOY_HW_PREDEFMIN) &&( HIWORD(phdi->guidProduct.Data1) < MSFT_SYSTEM_PID + JOY_HW_PREDEFMAX ) ) ) { pcfg->hwc.dwType = HIWORD(phdi->guidProduct.Data1) - MSFT_SYSTEM_PID; pcfg->hwc.dwUsageSettings = JOY_US_PRESENT | JOY_US_VOLATILE; } else { /* * This value really does not matter much but ideally * should be greater than or equal to JOY_HW_PREDEFMAX * Add idJoy for best compatiblity with the old CPLs. */ pcfg->hwc.dwType = idJoy + JOY_HW_PREDEFMAX; pcfg->hwc.dwUsageSettings = JOY_US_PRESENT | JOY_US_VOLATILE | JOY_US_ISOEM; } if(pcfg && pvip->Usages[ecRz]) { pcfg->hwc.dwUsageSettings |= JOY_US_HASRUDDER; } pcfg->hwc.dwReserved = 0x0; /* * Default gain to nominal max so it does not get written * to the registry unless it has some other value. */ pcfg->dwGain = DI_FFNOMINALMAX; propi.pguid = DIPROP_FFGAIN; propi.dwDevType = DIPH_DEVICE; propi.iobj = 0xFFFFFFFF; hres = pdcb->lpVtbl->GetProperty(pdcb, &propi, &dipd.diph); if( SUCCEEDED(hres) ) { pcfg->dwGain = dipd.dwData; } else { // Failure to get gain is not crutial hres = S_OK; } if( pcfg->hwc.dwType >= JOY_HW_PREDEFMAX ) { #ifndef UNICODE char szType[20]; #endif /* * This should work, but it doesn't in Win98, bug! * * wsprintfW(pcfg->wszType, L"VID_%04X&PID_%04X", * LOWORD(didi.guidProduct.Data1), HIWORD(didi.guidProduct.Data1)); */ #ifdef UNICODE wsprintf(pcfg->wszType, VID_PID_TEMPLATE, LOWORD(phdi->guidProduct.Data1), HIWORD(phdi->guidProduct.Data1)); #else wsprintf(szType, VID_PID_TEMPLATE, LOWORD(phdi->guidProduct.Data1), HIWORD(phdi->guidProduct.Data1)); AToU(pcfg->wszType, cA(pcfg->wszType), szType); #endif } else { /* * Predefined types do not have type strings for the * uses the callers of this function need. */ ZeroX(pcfg->wszType); } if( fWinnt ) { // No callout on NT ZeroX(pcfg->wszCallout); } else { lstrcpyW( pcfg->wszCallout, L"joyhid.vxd" ); } } // end of filling pcfg's fields pdijti->dwSize = cbX(*pdijti); pdijti->hws.dwNumButtons = dc.dwButtons; pdijti->hws.dwFlags = pvip->dwFlags; ZeroX(pdijti->clsidConfig); propi.pguid = DIPROP_INSTANCENAME; propi.dwDevType = DIPH_DEVICE; propi.iobj = 0xFFFFFFFF; hres = pdcb->lpVtbl->GetProperty(pdcb, &propi, &dips.diph); if( hres != S_OK && lstrlenW(pdijti->wszDisplayName) != 0x0 ) { // Failure to get friendly name // We will try and use the OEM name from the registry lstrcpyW(dips.wsz, pdijti->wszDisplayName); //pdcb->lpVtbl->SetProperty(pdcb, &propi, &dips.diph); }else if( SUCCEEDED(hres) ) { // Use friendly name in the registry lstrcpyW(pdijti->wszDisplayName, dips.wsz); hres = S_OK; } } // GetDeviceInfo FAILED } // GetCapabilities FAILED Invoke_Release(&pdcb); } } else // No HID device for JoyID { hres = E_FAIL; } if( fBadCalData ) { hres = E_FAIL; } ExitProcX(hres); return hres; } /***************************************************************************** * * @doc INTERNAL * * @func HRESULT | JoyReg_JoyIdToDeviceInterface | * * Given a joystick ID number, obtain the device interface * corresponding to it. * * @parm UINT | idJoy | * * Joystick ID number, zero-based. * * @parm PVXDINITPARMS | pvip | * * Receives init parameters from the driver. * * @parm LPTSTR | ptszBuf | * * A buffer of size in which the device interface * path is built. * * @returns * A pointer to the part of the

buffer that * contains the actual device interface path. * *****************************************************************************/ LPTSTR EXTERNAL JoyReg_JoyIdToDeviceInterface_NT ( IN UINT idJoy, OUT PVXDINITPARMS pvip, OUT LPTSTR ptszBuf ) { HRESULT hres; DIJOYCONFIG cfg; DIJOYTYPEINFO dijti; DllEnterCrit(); ZeroX(cfg); ZeroX(dijti); cfg.dwSize = cbX(cfg); dijti.dwSize = cbX(dijti); hres = DIWdm_JoyHidMapping(idJoy, pvip, &cfg, &dijti ); if( SUCCEEDED(hres ) ) { AssertF( lstrlen(pvip->pFilenameBuffer) < MAX_PATH ); lstrcpy(ptszBuf, pvip->pFilenameBuffer); } DllLeaveCrit(); return ptszBuf; }