//=========================================================================== // dimaptst.cpp // // DirectInput Mapper test tool // // Build options: // Internal Test Tool // -DINTERNAL -DTESTAPP // // External DDK Configuration Tool // -DDDKAPP // // Functions: // WinMain // dimaptstMainDlgProc // dimaptstOnInitDialog // dimaptstOnClose // dimaptstOnCommand // dimaptstOnUpdateControlData // dmtGetCheckedRadioButton // // History: // 08/19/1999 - davidkl - created //=========================================================================== #define INITGUID #include "dimaptst.h" #include "dmtabout.h" #include "dmtinput.h" #include "dmtcfg.h" #include "dmttest.h" //#include "dmtwrite.h" #include "dmtstress.h" //--------------------------------------------------------------------------- #ifndef NTAPI #define NTAPI __stdcall #endif #ifndef NTSYSAPI #define NTSYSAPI __declspec(dllimport) #endif #ifndef NTSTATUS typedef LONG NTSTATUS; #endif #ifndef PCSZ typedef CONST char *PCSZ; #endif extern "C" { NTSYSAPI NTSTATUS NTAPI RtlCharToInteger(PCSZ szString, ULONG ulBase, ULONG *puValue); NTSYSAPI ULONG NTAPI RtlNtStatusToDosError(NTSTATUS nts); } //--------------------------------------------------------------------------- // app global variables HINSTANCE ghinst = NULL; HANDLE ghEvent = NULL; CRITICAL_SECTION gcritsect; //--------------------------------------------------------------------------- // file global variables //--------------------------------------------------------------------------- //=========================================================================== // WinMain // // App entry point // // Parameters: (see SDK help for parameter details) // HINSTANCE hinst // HINSTANCE hinstPrev // LPSTR szCmdParams // int nShow // // Returns: (see SDK help for return value details) // int // // History: // 08/19/1999 - davidkl - created //=========================================================================== int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hinstPrev, PSTR szCmdParams, int nShow) { //int n = 0; //JJ 64Bit Compat INT_PTR n = 0; // initialize DPF DbgInitialize(TRUE); DbgEnable(TRUE); // see if our ini file exists n = GetPrivateProfileIntA("0", "AI0", 0, GENRES_INI); if(0 == n) { // file does not exist // // inform user and bail MessageBoxA(NULL, "Please copy genre.ini to the current folder.", "Unable to locate genre.ini", MB_OK); return FALSE; } // initialize Win9x common controls (progress bars, etc) InitCommonControls(); // intialize COM if(FAILED(CoInitialize(NULL))) { DPF(0, "COM initialization failed... exiting"); return -1; } // save our instance handle ghinst = hinst; // create our critical section InitializeCriticalSection(&gcritsect); // create our signal event ghEvent = CreateEvent(NULL, TRUE, FALSE, NULL); // create our main dialog window n = DialogBoxParamA(hinst, MAKEINTRESOURCEA(IDD_MAIN), (HWND)NULL, dimaptstMainDlgProc, (LPARAM)NULL); if(-1 == n) { DPF(0, "WinMain - DialogBoxParamA returned an error (%d)", GetLastError()); } // done CloseHandle(ghEvent); DeleteCriticalSection(&gcritsect); CoUninitialize(); return (int)n; } //*** end WinMain() //=========================================================================== // dimaptstMainDlgProc // // Main application dialog processing function // // Parameters: (see SDK help for parameter details) // HWND hwnd // UINT uMsg // WPARAM wparam // LPARAM lparam // // Returns: (see SDK help for return value details) // BOOL // // History: // 08/19/1999 - davidkl - created //=========================================================================== /*BOOL*/INT_PTR CALLBACK dimaptstMainDlgProc(HWND hwnd, UINT uMsg, WPARAM wparam, LPARAM lparam) { switch(uMsg) { case WM_INITDIALOG: return dimaptstOnInitDialog(hwnd, (HWND)wparam, lparam); case WM_CLOSE: return dimaptstOnClose(hwnd); case WM_COMMAND: return dimaptstOnCommand(hwnd, LOWORD(wparam), (HWND)lparam, HIWORD(wparam)); //JJ Comment: I am keeping the timer stuff around for now while getting rid of //input polling because we are going to use it later in a different way; I will //leave the timer stuff in for now and then add in the input stuff when more specific //decisions are made concerning *what* exact performance/implementation is desired. case WM_TIMER: return dimaptstOnTimer(hwnd, wparam); case WM_DMT_UPDATE_LISTS: return dimaptstOnUpdateLists(hwnd); } return FALSE; } //=========================================================================== // dimaptstOnInitDialog // // Handle WM_INITDIALOG processing for the main dialogfs // // Parameters: // // Returns: BOOL // // History: // 08/20/1999 - davidkl - created //=========================================================================== BOOL dimaptstOnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lparam) { HRESULT hRes = S_OK; /*int*/ //JJ 64Bit Compat UINT_PTR nIdx = 0; //LONG lPrev = 0L; //JJ 64Bit Compat LONG_PTR lPrev = 0; DMT_APPINFO *pdmtai = NULL; DMTGENRE_NODE *pNode = NULL; DPF(5, "dimaptstOnInitDialog"); // give the system menu our icon SendMessageA(hwnd, WM_SETICON, ICON_BIG, (LPARAM)LoadIcon(ghinst, MAKEINTRESOURCEA(IDI_DIMAPTST))); SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(ghinst, MAKEINTRESOURCEA(IDI_DIMAPTST))); // allocate the appinfo structure pdmtai = (DMT_APPINFO*)LocalAlloc(LMEM_FIXED, sizeof(DMT_APPINFO)); if(!pdmtai) { // serious app problem. // we need to stop things right here and now DPF(0, "dimaptstOnInitDialog - This is bad... " "We failed to allocate appinfo"); DPF(0, "dimaptstOnInitDialog - Please find someone " "to look at this right away"); DebugBreak(); return FALSE; } pdmtai->pGenreList = NULL; pdmtai->pSubGenre = NULL; pdmtai->pDeviceList = NULL; pdmtai->fStartWithDefaults = FALSE; // allocate the genre list hRes = dmtcfgCreateGenreList(&(pdmtai->pGenreList)); if(FAILED(hRes)) { // this is potentially very bad // ISSUE-2001/03/29-Marcand we fault if we hit this // really need to kill the app at this point DPF(0, "dimaptstOnInitDialog - This is bad... " "We failed to create genre list " "(%s == %08Xh)", dmtxlatHRESULT(hRes), hRes); DPF(0, "dimaptstOnInitDialog - Check to be sure that %s " " exists in the current directory", GENRES_INI); return FALSE; } // set the hwnd userdata SetLastError(0); //JJ- 64Bit compat change lPrev = SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pdmtai); if(!lPrev && GetLastError()) { // serious app problem. // we need to stop things right here and now DPF(0, "dimaptstOnInitDialog - This is bad... " "We failed to store pList"); DPF(0, "dimaptstOnInitDialog - Please find someone " "to look at this right away"); DebugBreak(); return FALSE; } // populate the controls // genre list pNode = pdmtai->pGenreList; while(pNode) { // add the name to the list nIdx = SendMessageA((HWND)GetDlgItem(hwnd, IDC_DEVICE_GENRES), CB_ADDSTRING, 0, (LPARAM)(pNode->szName)); // add the node to the item data SendMessageA(GetDlgItem(hwnd, IDC_DEVICE_GENRES), CB_SETITEMDATA, nIdx, (LPARAM)pNode); // next node pNode = pNode->pNext; } // set the selection to the first in the list SendMessageA(GetDlgItem(hwnd, IDC_DEVICE_GENRES), CB_SETCURSEL, 0, 0L); // populate the subgenre list SendMessageA(hwnd, WM_DMT_UPDATE_LISTS, 0, 0L); // set the testing option // CheckRadioButton(hwnd, // IDC_USE_INTEGRATED, // IDC_USE_CPL, // IDC_USE_CPL); #ifdef TESTAPP //*************************************** // Internal app specific control settings //*************************************** // set the verification option to automatic CheckRadioButton(hwnd, IDC_VERIFY_AUTOMATIC, IDC_VERIFY_MANUAL, IDC_VERIFY_AUTOMATIC); #endif // TESTAPP #ifdef DDKAPP //*************************************** // DDK Tool specific control settings //*************************************** // set default state for "start with defaults" CheckDlgButton(hwnd, IDC_START_WITH_DEFAULTS, BST_CHECKED); #endif // DDKAPP SendMessageA(hwnd, WM_COMMAND, IDC_ENUM_DEVICES, 0L); // done return TRUE; } //*** end dimaptstOnInitDialog() //=========================================================================== // dimaptstOnClose // // Handle WM_CLOSE processing for the main dialog // // Parameters: // // Returns: BOOL // // History: // 08/20/1999 - davidkl - created //=========================================================================== BOOL dimaptstOnClose(HWND hwnd) { HRESULT hRes = S_OK; HRESULT hr = S_OK; DMT_APPINFO *pdmtai = NULL; DPF(5, "dimaptstOnClose"); __try { // get appinfo //JJ- 64Bit Compat pdmtai = (DMT_APPINFO*)GetWindowLongPtr(hwnd, GWLP_USERDATA); if(!pdmtai) { DPF(0, "dimaptstOnClose - unable to retrieve app info"); hRes = E_UNEXPECTED; __leave; } // free appinfo // device list first hr = dmtinputFreeDeviceList(&(pdmtai->pDeviceList)); if(S_OK == hRes) { DPF(2, "dimaptstOnClose - dmtinputFreeDeviceList (%s == %08Xh)", dmtxlatHRESULT(hr), hr); hRes = hr; } pdmtai->pDeviceList = NULL; // then genre list hRes = dmtcfgFreeGenreList(&(pdmtai->pGenreList)); if(S_OK == hRes) { DPF(2, "dimaptstOnClose - dmtinputFreeGenreList (%s == %08Xh)", dmtxlatHRESULT(hr), hr); hRes = hr; } pdmtai->pGenreList = NULL; // parent structure if(LocalFree((HLOCAL)pdmtai)) { DPF(0, "dimaptstOnClose - LocalFree(app info) failed!"); if(S_OK == hRes) { hRes = DMT_S_MEMORYLEAK; } } pdmtai = NULL; } _finally { // time to leave EndDialog(hwnd, (int)hRes); PostQuitMessage((int)hRes); } // done return FALSE; } //*** end dimaptstOnClose() //=========================================================================== // dimaptstOnCommand // // Handle WM_COMMAND processing for the main dialog // // Parameters: // // Returns: BOOL // // History: // 08/20/1999 - davidkl - created //=========================================================================== BOOL dimaptstOnCommand(HWND hwnd, WORD wId, HWND hwndCtrl, WORD wNotifyCode) { HRESULT hRes = S_OK; BOOL fEnable = FALSE; BOOL fEnumSuitable = FALSE; //JJ Added 64Bit Compat LONG_PTR nIdx = -1; UINT_PTR u = 0; static UINT_PTR uGenSel = 0; static UINT uSubSel = 0; DMT_APPINFO *pdmtai = NULL; DMTDEVICE_NODE *pDevice = NULL; DMTGENRE_NODE *pGenre = NULL; DMTSUBGENRE_NODE *pSubGenre = NULL; #ifdef TESTAPP int nWidth = 597; int nHeight = 0; #endif // TESTAPP DPF(5, "dimaptstOnCommand"); // get app info (stored in hwnd userdata) //JJ- 64Bit Compat pdmtai = (DMT_APPINFO*)GetWindowLongPtr(hwnd, GWLP_USERDATA); if(!pdmtai) { // ISSUE-2001/03/29-timgill Needs error case handling } switch(wId) { case IDOK: //JJ FIX UI hRes = dmttestRunMapperCPL(hwnd, FALSE); break; case IDCANCEL: // ISSUE-2001/03/29-timgill need to check return value dmttestStopIntegrated(hwnd); break; case IDC_DEVICE_GENRES: // check for selection change if(CBN_DROPDOWN == wNotifyCode) { // memorize current selection uGenSel = SendMessageA(GetDlgItem(hwnd, IDC_DEVICE_GENRES), CB_GETCURSEL, 0, //JJ- 64Bit Compat //0L); 0); } if(CBN_SELCHANGE == wNotifyCode) { // selection changed // // get the new selection u = SendMessageA(GetDlgItem(hwnd, IDC_DEVICE_GENRES), CB_GETCURSEL, 0, 0L); if(uGenSel != u) { SendMessageA(hwnd, WM_DMT_UPDATE_LISTS, 0, 0L); } } break; case IDC_SUBGENRES: #ifndef DDKAPP // check for selection change if(CBN_DROPDOWN == wNotifyCode) { // memorize current selection uSubSel = SendMessageA(GetDlgItem(hwnd, IDC_SUBGENRES), CB_GETCURSEL, 0, 0L); } if(CBN_SELCHANGE == wNotifyCode) { // selection changed // // get the new selection u = SendMessageA(GetDlgItem(hwnd, IDC_SUBGENRES), CB_GETCURSEL, 0, 0L); if(uSubSel != u) { // clear the device combo box SendMessageA(GetDlgItem(hwnd, IDC_DEVICE_LIST), CB_RESETCONTENT, 0, 0L); // release device list dmtinputFreeDeviceList(&(pdmtai->pDeviceList)); // release the mapping lists for each subgenre dmtcfgFreeAllMappingLists(pdmtai->pGenreList); // disable appropriate controls dimaptstPostEnumEnable(hwnd, FALSE); } } #endif break; case IDC_ENUM_DEVICES: // ISSUE-2001/03/29-timgill Long conditional branch // should really make a sep. fn /* #ifdef DDKAPP // we only want to enumerate all gaming // devices if we are the DDK tool fEnumSuitable = FALSE; #else */ fEnumSuitable = TRUE; u = SendMessageA(GetDlgItem(hwnd, IDC_SUBGENRES), CB_GETCURSEL, 0, 0L); pSubGenre = (DMTSUBGENRE_NODE*)SendMessageA(GetDlgItem(hwnd, IDC_SUBGENRES), CB_GETITEMDATA, u, 0L); if(!pSubGenre) { // ISSUE-2001/03/29-timgill Needs error case handling } //#endif // first, free the existing device list hRes = dmtinputFreeDeviceList(&(pdmtai->pDeviceList)); if(FAILED(hRes)) { // ISSUE-2001/03/29-timgill Needs error case handling } // then, flush the combo box SendMessageA(GetDlgItem(hwnd, IDC_DEVICE_LIST), CB_RESETCONTENT, 0, 0L); // now, re-create the device list hRes = dmtinputCreateDeviceList(hwnd, fEnumSuitable, pSubGenre, &(pdmtai->pDeviceList)); if(FAILED(hRes)) { // ISSUE-2001/03/29-timgill Needs error case handling } // free the existing mapping lists dmtcfgFreeAllMappingLists(pdmtai->pGenreList); // create the mapping lists within the subgenres hRes = dmtcfgCreateAllMappingLists(pdmtai); if(FAILED(hRes)) { // ISSUE-2001/03/29-timgill Needs error case handling } // populate the devices control pDevice = pdmtai->pDeviceList; while(pDevice) { // add device name nIdx = SendMessageA(GetDlgItem(hwnd, IDC_DEVICE_LIST), CB_ADDSTRING, 0, (LPARAM)&(pDevice->szName)); // add device node to item data SendMessageA(GetDlgItem(hwnd, IDC_DEVICE_LIST), CB_SETITEMDATA, nIdx, (LPARAM)pDevice); // next device pDevice = pDevice->pNext; } // select the 1st entry SendMessageA(GetDlgItem(hwnd, IDC_DEVICE_LIST), CB_SETCURSEL, 0, 0L); // enable appropriate ui elements dimaptstPostEnumEnable(hwnd, TRUE); break; #ifdef TESTAPP //*************************************** // Internal app specific message handling //*************************************** case IDC_VERIFY_MANUAL: case IDC_VERIFY_AUTOMATIC: // enable/disable manual override option fEnable = (BOOL)(IDC_VERIFY_MANUAL - dmtGetCheckedRadioButton(hwnd, IDC_VERIFY_AUTOMATIC, IDC_VERIFY_MANUAL)); EnableWindow(GetDlgItem(hwnd, IDC_VERIFY_MANUAL_OVERRIDE), fEnable); break; case IDC_STRESS_MODE: // expand/shrink dialog nHeight = IsDlgButtonChecked(hwnd, IDC_STRESS_MODE) ? 490 : 361; SetWindowPos(hwnd, HWND_TOP, 0, 0, nWidth, nHeight, SWP_NOMOVE | SWP_NOOWNERZORDER); // enable / disable stress configuration & launch fEnable = (BOOL)IsDlgButtonChecked(hwnd, IDC_STRESS_MODE); // EnableWindow(GetDlgItem(hwnd, IDC_CONFIGURE), fEnable); EnableWindow(GetDlgItem(hwnd, IDC_STRESS_START), fEnable); break; #endif // TESTAPP #ifdef DDKAPP case IDC_LAUNCH_CPL_EDIT_MODE: // get the currently selected device? nIdx = SendMessageA(GetDlgItem(hwnd, IDC_DEVICE_LIST), CB_GETCURSEL, 0, 0L); if (nIdx == CB_ERR) { // Error has occurred. Most likely no device is available. MessageBox(hwnd, "No device selected.", "Error", MB_OK); return TRUE; } pDevice = (DMTDEVICE_NODE*)SendMessageA(GetDlgItem(hwnd, IDC_DEVICE_LIST), CB_GETITEMDATA, nIdx, 0L); if(!pDevice) { // ISSUE-2001/03/29-timgill Needs error case handling } // launch the mapper cpl in edit mode hRes = dmttestRunMapperCPL(hwnd, TRUE); if(FAILED(hRes)) { // ISSUE-2001/03/29-timgill Needs error case handling } break; #endif // DDKAPP } // done return FALSE; } //*** end dimaptstOnCommand() //=========================================================================== // dimaptstOnTimer // // Handles WM_TIMER messages for the main app dialog // // Parameters: // // Returns: BOOL // // History: // 11/02/1999 - davidkl - created //=========================================================================== BOOL dimaptstOnTimer(HWND hwnd, WPARAM wparamTimerId) { //int nSel = -1; //JJ 64Bit Compat LONG_PTR nSel = -1; DMTDEVICE_NODE *pDevice = NULL; DPF(5, "dimaptstOnTimer - ID == %d", wparamTimerId); if(ID_POLL_TIMER == wparamTimerId) { // get the current device nSel = SendMessageA(GetDlgItem(hwnd, IDC_DEVICE_LIST), CB_GETCURSEL, 0, 0L); if(-1 == nSel) { DPF(0, "dimaptstOnTimer - invalid device selection"); return FALSE; } pDevice = (DMTDEVICE_NODE*)SendMessageA(GetDlgItem(hwnd, IDC_DEVICE_LIST), CB_GETITEMDATA, nSel, 0L); if(!pDevice) { DPF(0, "dimaptstOnTimer - failed to retrieve device node"); return FALSE; } // get data from the device //JJ Removed //dmttestGetInput(hwnd, // pDevice); } // done return FALSE; } //*** end dimaptstOnTimer() //=========================================================================== // dimaptstOnUpdateLists // // Updates the subgenre list in response to a genre bucket change // // NOTE: INTERNAL only - This also clears the devices list, frees // all associated linked lists and performs some window enabling/disabling // tasks. // // Parameters: // HWND hwnd - handle to app window // // Returns: BOOL // // History: // 10/01/1999 - davidkl - created //=========================================================================== BOOL dimaptstOnUpdateLists(HWND hwnd) { //JJ 64Bit Compat UINT_PTR uSel = 0; DMTGENRE_NODE *pGenre = NULL; DMTSUBGENRE_NODE *pSubNode = NULL; DMT_APPINFO *pdmtai = NULL; // get the genre bucket node uSel = SendMessageA(GetDlgItem(hwnd, IDC_DEVICE_GENRES), CB_GETCURSEL, 0, 0L); pGenre = (DMTGENRE_NODE*)SendMessageA(GetDlgItem(hwnd, IDC_DEVICE_GENRES), CB_GETITEMDATA, uSel, 0L); if(!pGenre) { // this is bad DebugBreak(); return TRUE; } // clear the existing list contents SendMessageA(GetDlgItem(hwnd, IDC_SUBGENRES), CB_RESETCONTENT, 0, 0L); // update (sub)genres list pSubNode = pGenre->pSubGenreList; while(pSubNode) { uSel = SendMessageA(GetDlgItem(hwnd, IDC_SUBGENRES), CB_ADDSTRING, 0, (LPARAM)(pSubNode->szName)); SendMessageA(GetDlgItem(hwnd, IDC_SUBGENRES), CB_SETITEMDATA, uSel, (LPARAM)pSubNode); // next subgenre pSubNode = pSubNode->pNext; } // select the first list entry SendMessageA(GetDlgItem(hwnd, IDC_SUBGENRES), CB_SETCURSEL, 0, 0L); #ifndef DDKAPP //============================================ // only do this part for SDK and INTERNAL apps //============================================ // get the device list pdmtai = (DMT_APPINFO*)GetWindowLong(hwnd, GWL_USERDATA); if(!pdmtai) { // ISSUE-2001/03/29-timgill Needs error case handling } // clear the device combo box SendMessageA(GetDlgItem(hwnd, IDC_DEVICE_LIST), CB_RESETCONTENT, 0, 0L); // release device list dmtinputFreeDeviceList(&(pdmtai->pDeviceList)); // release the mapping lists for each subgenre dmtcfgFreeAllMappingLists(pdmtai->pGenreList); // disable appropriate controls dimaptstPostEnumEnable(hwnd, FALSE); #endif // done return FALSE; } //*** end dimaptstOnUpdateLists() //=========================================================================== // dmtGetCheckedRadioButton // // Returns the checked radio button in a group. // // Parameters: // // Returns: // // History: // 08/25/1998 - davidkl - created (copied from dmcs sources) //=========================================================================== UINT dmtGetCheckedRadioButton(HWND hWnd, UINT uCtrlStart, UINT uCtrlStop) { UINT uCurrent = 0; for(uCurrent = uCtrlStart; uCurrent <= uCtrlStop; uCurrent++) { if(IsDlgButtonChecked(hWnd, uCurrent)) { return uCurrent; } } // if we get here, none were checked return 0; } //*** end dmtGetCheckedRadioButton() //=========================================================================== // dimaptstPostEnumEnable // // Enables/disables main app UI elements in response to enumerating devices // // Parameters: // HWND hwnd - main app window handle // BOOL fEnable - enable or disable controls // // Returns: nothing // // History: // 10/01/1999 - davidkl - created //=========================================================================== void dimaptstPostEnumEnable(HWND hwnd, BOOL fEnable) { UINT u = 0; // devices list EnableWindow(GetDlgItem(hwnd, IDC_DEVICES_LABEL), fEnable); EnableWindow(GetDlgItem(hwnd, IDC_DEVICE_LIST), fEnable); //JJ UI FIX // test controls //for(u = IDC_TEST_CTRL_GROUP; u <= IDC_USE_CPL; u++) //{ // EnableWindow(GetDlgItem(hwnd, u), fEnable); // } // ISSUE-2000/02/21-timgill disable integration control and start button for the preview // should be re-enabled once test mode code is fixed // EnableWindow(GetDlgItem(hwnd, IDC_USE_INTEGRATED), FALSE); // start button // EnableWindow(GetDlgItem(hwnd, IDOK), fEnable); #ifdef DDKAPP // mapping file group for(u = IDC_MAPPING_FILE_GROUP; u <= IDC_LAUNCH_CPL_EDIT_MODE; u++) { EnableWindow(GetDlgItem(hwnd, u), TRUE); } #else #ifdef TESTAPP // verification mode for(u = IDC_VERIFY_GROUP; u <= IDC_VERIFY_MANUAL; u++) { EnableWindow(GetDlgItem(hwnd, u), TRUE); } // this will enable the manual overrride option as appropriate SendMessageA(hwnd, WM_COMMAND, IDC_VERIFY_AUTOMATIC, 0L); // this will enable the configuration button and // expand the application window as appropriate SendMessageA(hwnd, WM_COMMAND, IDC_STRESS_MODE, 0L); #endif #endif } //*** end dimaptstPostEnumEnable() //=========================================================================== //=========================================================================== //=========================================================================== //=========================================================================== //=========================================================================== //===========================================================================