Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1578 lines
52 KiB

  1. /*
  2. File: add.cpp
  3. Project: Universal Joystick Control Panel OLE Client
  4. Author: Brycej
  5. Date: 14/Feb/97
  6. Comments:
  7. window proc for add dialog
  8. Copyright (c) 1995, Microsoft Corporation
  9. */
  10. #include <afxcmn.h>
  11. #include <windowsx.h>
  12. #include <regstr.h> // for REGSTR_VAL_JOYOEMNAME reference!
  13. #include "cpanel.h"
  14. #include "joyarray.h"
  15. #include <initguid.h>
  16. #pragma warning(disable:4200)
  17. #include <gameport.h>
  18. #pragma warning(default:4200)
  19. // table of default joystick configs
  20. extern WCHAR *pwszTypeArray[MAX_DEVICES]; // List of enumerated gameport devices
  21. extern WCHAR *pwszGameportBus[MAX_BUSSES]; // List of enumerated gameport buses
  22. extern PJOY pAssigned[MAX_ASSIGNED]; // List of assigned devices
  23. extern BYTE nAssigned; // Number of elements in pAssigned array
  24. extern BYTE nTargetAssigned; // Number of elements expected when pending adds complete
  25. extern BYTE nReEnum; // Counter used to decide when to reenumerate
  26. extern GUID guidOccupied[MAX_BUSSES]; //Whether the gameport bus has been occupied.
  27. extern BYTE nGameportBus, nGamingDevices;
  28. extern IDirectInputJoyConfig *pDIJoyConfig;
  29. extern short iItem;
  30. extern short nFlags; // Flags set in CPANEL.CPP!
  31. // extern functions defined in CPANEL.CPP
  32. extern void OnContextMenu(WPARAM wParam, LPARAM lParam);
  33. extern void OnHelp (LPARAM);
  34. // local message handlers
  35. static BOOL OnInitDialog(HWND, HWND, LPARAM);
  36. static void OnClose(HWND);
  37. static void OnCommand(HWND, int, HWND, UINT);
  38. static char AddSelectedItem( HWND hDlg );
  39. static BOOL UpdateListCtrl ( HWND hCtrl );
  40. static char GetNextAvailableID( void );
  41. static BOOL IsTypeActive( short *nArrayIndex );
  42. static BOOL GetNextAvailableVIDPID(LPWSTR lpwszType );
  43. //static BOOL IsCustomType(BYTE nIndex);
  44. static void PostHScrollBar(HWND hCtrl, LPCTSTR lpStr, BYTE nStrLen);
  45. extern const DWORD g_aHelpIDs[];
  46. extern HINSTANCE ghInstance;
  47. LPTSTR lpszAutoDetect;
  48. const int NO_ITEM = -1;
  49. #define MAX_ANALOG_BUTTONS 4
  50. #define MAX_ANALOG_AXIS 4
  51. // This will become a problem when we support > 500 ports!
  52. #define AUTODETECT_PORT 100
  53. // Consider achieving this from calculation of width of listview
  54. static short iAddItem = NO_ITEM;
  55. BOOL WINAPI AddDialogProc(HWND hDlg, ULONG uMsg, WPARAM wParam, LPARAM lParam)
  56. {
  57. switch( uMsg )
  58. {
  59. case WM_DESTROY:
  60. DestroyIcon((HICON)SendMessage(hDlg, WM_GETICON, (WPARAM)ICON_SMALL, 0));
  61. if( nGameportBus > 1 )
  62. if( lpszAutoDetect )
  63. delete[] (lpszAutoDetect);
  64. break;
  65. case WM_LBUTTONDOWN:
  66. // Click Drag service for PropSheets!
  67. PostMessage(hDlg, WM_NCLBUTTONDOWN, (WPARAM)HTCAPTION, lParam);
  68. break;
  69. case WM_INITDIALOG:
  70. return(BOOL)HANDLE_WM_INITDIALOG(hDlg, wParam, lParam, OnInitDialog);
  71. case WM_COMMAND:
  72. HANDLE_WM_COMMAND(hDlg, wParam, lParam, OnCommand);
  73. return(1);
  74. case WM_VKEYTOITEM:
  75. if( LOWORD(wParam) == VK_DELETE )
  76. {
  77. HWND hWnd = GetDlgItem(hDlg, IDC_DEVICE_LIST);
  78. // determine if it's a custom type... if so... delete it
  79. // Get the next object with the SELECTED attribute
  80. iAddItem = (short)::SendMessage(hWnd, LB_GETCURSEL, 0, 0);
  81. short nArrayIndex = (short)::SendMessage(hWnd, LB_GETITEMDATA, (WPARAM)iAddItem, 0);
  82. // test to make sure they aren't trying to delete a standard type
  83. if( *pwszTypeArray[nArrayIndex] == L'#' )
  84. break;
  85. // test that the device is a custom type (user or IHV defined)
  86. // ISSUE-2001/03/29-timgill the number of times we retrieve the same data is ridiculous
  87. LPDIJOYTYPEINFO lpdiJoyInfo = new (DIJOYTYPEINFO);
  88. ASSERT (lpdiJoyInfo);
  89. if( lpdiJoyInfo )
  90. {
  91. /*
  92. * warning, abuse of S_OK == 0 == strcmp( identical strings ) ahead
  93. */
  94. HRESULT CmpRes;
  95. ZeroMemory(lpdiJoyInfo, sizeof(*lpdiJoyInfo));
  96. lpdiJoyInfo->dwSize = sizeof(*lpdiJoyInfo);
  97. /*
  98. * Test the hardware ID
  99. */
  100. CmpRes = pDIJoyConfig->GetTypeInfo(pwszTypeArray[nArrayIndex], (LPDIJOYTYPEINFO)lpdiJoyInfo, DITC_HARDWAREID);
  101. if( SUCCEEDED( CmpRes ) )
  102. {
  103. #ifndef WINNT
  104. if( lpdiJoyInfo->wszHardwareId[0] == L'\0' )
  105. {
  106. /*
  107. * No hardware ID, so look for a callout VxD
  108. * If there is none, we have a custom type.
  109. */
  110. CmpRes = pDIJoyConfig->GetTypeInfo(pwszTypeArray[nArrayIndex], (LPDIJOYTYPEINFO)lpdiJoyInfo, DITC_CALLOUT);
  111. CmpRes = ( SUCCEEDED( CmpRes ) && ( lpdiJoyInfo->wszCallout[0] == L'\0' ) )
  112. ? S_OK : S_FALSE;
  113. }
  114. else
  115. #endif
  116. {
  117. const WCHAR wszAnalogRoot[] = L"gameport\\vid_045e&pid_01";
  118. CmpRes = (HRESULT)_wcsnicmp( lpdiJoyInfo->wszHardwareId, wszAnalogRoot,
  119. (sizeof(wszAnalogRoot)/sizeof(wszAnalogRoot[0]) ) - 1 );
  120. }
  121. }
  122. else
  123. {
  124. CmpRes = S_FALSE;
  125. }
  126. // clean-up!
  127. delete (lpdiJoyInfo);
  128. if( CmpRes != S_OK )
  129. {
  130. // This is not an analog type so leave alone
  131. break;
  132. }
  133. }
  134. else
  135. {
  136. // If we can't test the type, do nothing
  137. break;
  138. }
  139. // test to make sure you are not deleting objects
  140. if( IsTypeActive(&nArrayIndex) )
  141. {
  142. Error((short)IDS_GEN_AREYOUSURE_TITLE, (short)IDS_NO_REMOVE);
  143. break;
  144. }
  145. // This buffer has to be big enough for the name and the "are you sure..." message!
  146. LPTSTR pszMsg = new TCHAR[MAX_STR_LEN+STR_LEN_64];
  147. ASSERT (pszMsg);
  148. LPTSTR pszTitle = new TCHAR[STR_LEN_128];
  149. ASSERT (pszTitle);
  150. // Query user if they are sure!
  151. VERIFY(LoadString(ghInstance, IDS_GEN_AREYOUSURE, pszTitle, MAX_STR_LEN));
  152. LPTSTR pszTmp = new TCHAR[(short)SendMessage(hWnd, LB_GETTEXTLEN, (WPARAM)iAddItem, 0)+1];
  153. ASSERT (pszTmp);
  154. SendMessage(hWnd, LB_GETTEXT, (WPARAM)iAddItem, (LPARAM)(LPCTSTR)pszTmp);
  155. wsprintf( pszMsg, pszTitle, pszTmp);
  156. if( pszTmp )
  157. delete[] (pszTmp);
  158. VERIFY(LoadString(ghInstance, IDS_GEN_AREYOUSURE_TITLE, pszTitle, STR_LEN_128));
  159. HRESULT hr = MessageBox(hWnd, pszMsg, pszTitle, MB_ICONQUESTION | MB_YESNO | MB_APPLMODAL);
  160. if( pszMsg ) delete[] (pszMsg);
  161. if( pszTitle ) delete[] (pszTitle);
  162. if( IDYES == hr )
  163. {
  164. if( SUCCEEDED(hr = pDIJoyConfig->Acquire()) )
  165. {
  166. // traverse the list and delete any configuration that may have this type assigned to it!
  167. //DeleteAssignedType( pwszTypeArray[nArrayIndex] );
  168. // returns E_ACCESSDENIED if it's a default item.
  169. hr = pDIJoyConfig->DeleteType(pwszTypeArray[nArrayIndex]);
  170. ASSERT(SUCCEEDED(hr));
  171. pDIJoyConfig->Unacquire();
  172. // the dec is for the zero based device list!
  173. // decrement the indexes
  174. nGamingDevices--;
  175. // don't move if you're on the last entry!
  176. if( nArrayIndex != nGamingDevices )
  177. {
  178. // To avoid deleting and recreating...
  179. // Let's see if we have room to put this string!
  180. BYTE nLen = (BYTE)wcslen(pwszTypeArray[nArrayIndex])+1;
  181. // Make sure pwszTypeArray[nArrayIndex] is larger than pwszTypeArray[nCount]
  182. if( nLen < (BYTE)wcslen(pwszTypeArray[nGamingDevices])+1 )
  183. {
  184. if( pwszTypeArray[nArrayIndex] )
  185. free(pwszTypeArray[nArrayIndex]);
  186. pwszTypeArray[nArrayIndex] = _wcsdup(pwszTypeArray[nGamingDevices]);
  187. ASSERT (pwszTypeArray[nArrayIndex]);
  188. }
  189. // move the end element to the place of the deleted one
  190. else wcsncpy(pwszTypeArray[nArrayIndex], pwszTypeArray[nGamingDevices], wcslen(pwszTypeArray[nGamingDevices])+1);
  191. // update the extra memory to reflect the new index!
  192. // First, find the item in the listbox and get the index...
  193. LPDIJOYTYPEINFO_DX5 lpdiJoyInfo = new (DIJOYTYPEINFO_DX5);
  194. ASSERT (lpdiJoyInfo);
  195. ZeroMemory(lpdiJoyInfo, sizeof(DIJOYTYPEINFO_DX5));
  196. lpdiJoyInfo->dwSize = sizeof(DIJOYTYPEINFO_DX5);
  197. if( SUCCEEDED(pDIJoyConfig->GetTypeInfo(pwszTypeArray[nArrayIndex], (LPDIJOYTYPEINFO)lpdiJoyInfo, DITC_DISPLAYNAME)) )
  198. {
  199. char n = (char)SendMessage(hWnd, LB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)lpdiJoyInfo->wszDisplayName);
  200. SendMessage(hWnd, LB_SETITEMDATA, (WPARAM)n, (LPARAM)nArrayIndex);
  201. }
  202. // clean-up!
  203. if( lpdiJoyInfo )
  204. delete (lpdiJoyInfo);
  205. }
  206. // delete the end element from the array
  207. if( pwszTypeArray[nGamingDevices] )
  208. {
  209. free(pwszTypeArray[nGamingDevices]);
  210. pwszTypeArray[nGamingDevices] = 0;
  211. }
  212. // Remove the entry from the list control
  213. SendMessage(hWnd, LB_DELETESTRING, (WPARAM)iAddItem, 0);
  214. // Enable the buttons!
  215. if( nGamingDevices < MAX_DEVICES-1 )
  216. {
  217. HWND hParent = GetParent(hWnd);
  218. ASSERT (hParent);
  219. PostDlgItemEnableWindow(hParent, IDC_CUSTOM, TRUE);
  220. PostDlgItemEnableWindow(hParent, IDC_ADD_NEW, TRUE);
  221. }
  222. if( iAddItem != nGamingDevices-1 )
  223. iAddItem--;
  224. // Set the focus to the next available item
  225. PostMessage(hWnd, LB_SETCURSEL, (WPARAM)(iAddItem == NO_ITEM) ? 0 : iAddItem, 0);
  226. }
  227. }
  228. break;
  229. } else return(-1);
  230. // case WM_NOTIFY:
  231. /// return HANDLE_WM_NOTIFY(hDlg, wParam, lParam, OnNotify);
  232. case WM_HELP:
  233. OnHelp(lParam);
  234. return(1);
  235. case WM_CONTEXTMENU:
  236. OnContextMenu(wParam, lParam);
  237. return(1);
  238. }
  239. return(0);
  240. }
  241. BOOL OnInitDialog(HWND hDlg, HWND hWnd, LPARAM lParam)
  242. {
  243. HICON hIcon = (HICON)LoadImage(ghInstance, MAKEINTRESOURCE(IDI_CPANEL), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE);
  244. ASSERT (hIcon);
  245. if( hIcon )
  246. ::PostMessage(hDlg, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)hIcon);
  247. if( nFlags & ON_NT )
  248. DestroyWindow(GetDlgItem(hDlg, IDC_WDM));
  249. else
  250. {
  251. HKEY hKey;
  252. // remove the WDM flag unless otherwise specified!
  253. if( RegOpenKey(HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Control\\MediaResources\\joystick\\<FixedKey>"), &hKey) == ERROR_SUCCESS )
  254. {
  255. DWORD n;
  256. DWORD dwSize = sizeof (DWORD);
  257. if( RegQueryValueEx(hKey, TEXT("UseWDM"), 0, 0, (LPBYTE)&n, &dwSize) == ERROR_SUCCESS )
  258. {
  259. if( n )
  260. DestroyWindow(GetDlgItem(hDlg, IDC_WDM));
  261. }
  262. }
  263. RegCloseKey(hKey);
  264. }
  265. // a simple debug test to verify that the template hasn't gotten DIALOGEX style again!
  266. HWND hCtrl = GetDlgItem(hDlg, IDC_DEVICE_LIST);
  267. ASSERT (hCtrl);
  268. // Fill up the Device List
  269. if( !UpdateListCtrl(hCtrl) )
  270. {
  271. TRACE(TEXT("JOY.CPL: ADD.CPP: Failed UpdateListCtrl!\n"));
  272. return(FALSE);
  273. }
  274. // If there is only one, don't confuse the user with the combo box
  275. if( nGameportBus > 1 )
  276. {
  277. // Allocate for AutoDetect Gameport!
  278. lpszAutoDetect = new (TCHAR[STR_LEN_32]);
  279. ASSERT (lpszAutoDetect);
  280. VERIFY(LoadString(ghInstance, IDS_AUTO_DETECT, lpszAutoDetect, STR_LEN_32));
  281. hCtrl = GetDlgItem(hDlg, IDC_GAMEPORTLIST);
  282. ASSERT (hCtrl);
  283. if( !PopulatePortList(hCtrl) )
  284. {
  285. TRACE(TEXT("JOY.CPL: ADD.CPP: Failed PopulatePortList!\n"));
  286. return(FALSE);
  287. }
  288. LPDIJOYTYPEINFO lpdiJoyInfo = new DIJOYTYPEINFO;
  289. ASSERT (lpdiJoyInfo);
  290. ZeroMemory(lpdiJoyInfo, sizeof(DIJOYTYPEINFO));
  291. lpdiJoyInfo->dwSize = sizeof(DIJOYTYPEINFO);
  292. VERIFY(SUCCEEDED(pDIJoyConfig->GetTypeInfo(pwszTypeArray[0], (LPDIJOYTYPEINFO)lpdiJoyInfo, DITC_FLAGS1)));
  293. // Search for AutoDetect in the list!
  294. char nIndex = (char)::SendMessage(hCtrl, CB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)(LPCTSTR)lpszAutoDetect);
  295. // If it's got the JOYTYPE_NOAUTODETECTGAMEPORT flag, remove AutoDetect from the ListCtrl
  296. if( lpdiJoyInfo->dwFlags1 & JOYTYPE_NOAUTODETECTGAMEPORT )
  297. {
  298. // it could fail because the entry is not available...
  299. if( nIndex != CB_ERR )
  300. ::SendMessage(hCtrl, CB_DELETESTRING, (WPARAM)nIndex, 0);
  301. }
  302. // Otherwise, verify that AutoDetect is present... if not, add it!
  303. else
  304. {
  305. // it could fail because the entry is not available...
  306. if( nIndex == CB_ERR )
  307. ::SendMessage(hCtrl, CB_SETITEMDATA, ::SendMessage(hCtrl, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)lpszAutoDetect), AUTODETECT_PORT);
  308. }
  309. if( lpdiJoyInfo )
  310. delete (lpdiJoyInfo);
  311. SetWindowPos( hCtrl, NULL, NULL, NULL, NULL, NULL,
  312. SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW);
  313. SetWindowPos( GetDlgItem(hDlg, IDC_GAMEPORT), NULL, NULL, NULL, NULL, NULL,
  314. SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW);
  315. }
  316. // blj: Warning Message that you can't add any more devices!
  317. if( nGamingDevices == MAX_DEVICES-1 )
  318. {
  319. // Disable the Custom Button!
  320. PostDlgItemEnableWindow(hDlg, IDC_CUSTOM, FALSE);
  321. PostDlgItemEnableWindow(hDlg, IDC_ADD_NEW, FALSE);
  322. // Give the user a error message!
  323. Error((short)IDS_MAX_DEVICES_TITLE, (short)IDS_MAX_DEVICES_MSG);
  324. }
  325. return(0);
  326. }
  327. ///////////////////////////////////////////////////////////////////////////////
  328. // FUNCTION: OnCommand(HWND hDlg, int id, HWND hWndCtl, UINT code)
  329. //
  330. // PARAMETERS: hDlg -
  331. // id -
  332. // hWndCtl -
  333. // code -
  334. //
  335. // PURPOSE: WM_COMMAND message handler
  336. ///////////////////////////////////////////////////////////////////////////////
  337. void OnCommand(HWND hDlg, int id, HWND hWndCtl, UINT code)
  338. {
  339. switch( id )
  340. {
  341. case IDC_ADD_NEW:
  342. if( SUCCEEDED(pDIJoyConfig->AddNewHardware(hDlg, GUID_MediaClass)) )
  343. {
  344. ClearArrays();
  345. if( FAILED(pDIJoyConfig->EnumTypes((LPDIJOYTYPECALLBACK)DIEnumJoyTypeProc, NULL)) )
  346. {
  347. TRACE(TEXT("JOY.CPL: ADD.CPP: Failed BuildEnumList!\n"));
  348. return;
  349. }
  350. // Warning Message that you can't add any more devices!
  351. if( nGamingDevices == MAX_DEVICES-1 )
  352. {
  353. // Disable the Custom Button!
  354. PostDlgItemEnableWindow(hDlg, IDC_CUSTOM, FALSE);
  355. PostDlgItemEnableWindow(hDlg, IDC_ADD_NEW, FALSE);
  356. // Give the user a error message!
  357. Error((short)IDS_MAX_DEVICES_TITLE, (short)IDS_MAX_DEVICES_MSG);
  358. }
  359. if( !UpdateListCtrl(GetDlgItem(hDlg, IDC_DEVICE_LIST)) )
  360. {
  361. TRACE(TEXT("JOY.CPL: ADD.CPP: Failed to update the list control on the add page!\n"));
  362. return;
  363. }
  364. }
  365. break;
  366. case IDC_CUSTOM:
  367. // DialogBox returns either IDCANCEL or the index into the list of
  368. // defined types!
  369. if( IDOK == DialogBox(ghInstance, (PTSTR)IDD_CUSTOM, hDlg, (DLGPROC)CustomDialogProc) )
  370. {
  371. HWND hCtrl = GetDlgItem(hDlg, IDC_DEVICE_LIST);
  372. // blj: Warning Message that you can't add any more devices!
  373. if( nGamingDevices == MAX_DEVICES-1 )
  374. {
  375. // Disable the Custom Button!
  376. PostDlgItemEnableWindow(hDlg, IDC_CUSTOM, FALSE);
  377. // Give the user a error message!
  378. Error((short)IDS_MAX_DEVICES_TITLE, (short)IDS_MAX_DEVICES_MSG);
  379. }
  380. // Now, put the focus on the newly created item!
  381. LPDIJOYTYPEINFO_DX5 lpdiJoyInfo = new (DIJOYTYPEINFO_DX5);
  382. ASSERT (lpdiJoyInfo);
  383. ZeroMemory(lpdiJoyInfo, sizeof(DIJOYTYPEINFO_DX5));
  384. lpdiJoyInfo->dwSize = sizeof(DIJOYTYPEINFO_DX5);
  385. // Get nGamingDevices from pwszTypeArray
  386. // Subtract 1 from nGamingDevices because the list is 0 based!
  387. if( SUCCEEDED(pDIJoyConfig->GetTypeInfo(pwszTypeArray[nGamingDevices-1], (LPDIJOYTYPEINFO)lpdiJoyInfo, DITC_DISPLAYNAME | DITC_REGHWSETTINGS)) )
  388. {
  389. #ifdef _UNICODE
  390. iAddItem = (short)SendMessage(hCtrl, LB_ADDSTRING, 0, (LPARAM)(LPCTSTR)lpdiJoyInfo->wszDisplayName);
  391. SendMessage(hCtrl, LB_SETITEMDATA, (WPARAM)iAddItem, (LPARAM)nGamingDevices-1);
  392. PostHScrollBar(hCtrl, lpdiJoyInfo->wszDisplayName, (BYTE)wcslen(lpdiJoyInfo->wszDisplayName));
  393. #else
  394. USES_CONVERSION;
  395. iAddItem = (short)SendMessage(hCtrl, LB_ADDSTRING, 0, (LPARAM)(LPCTSTR)W2A(lpdiJoyInfo->wszDisplayName));
  396. SendMessage(hCtrl, LB_SETITEMDATA, (WPARAM)iAddItem, (LPARAM)nGamingDevices-1);
  397. PostHScrollBar(hCtrl, W2A(lpdiJoyInfo->wszDisplayName), (BYTE)wcslen(lpdiJoyInfo->wszDisplayName));
  398. #endif
  399. // SetFocus to that item!
  400. SendMessage(hCtrl, LB_SETCURSEL, (WPARAM)iAddItem, 0);
  401. OnCommand(hDlg, IDC_DEVICE_LIST, 0, LBN_SELCHANGE);
  402. }
  403. // clean-up!
  404. if( lpdiJoyInfo )
  405. delete (lpdiJoyInfo);
  406. }
  407. break;
  408. case IDC_DEVICE_LIST:
  409. if( code == LBN_SELCHANGE )
  410. {
  411. iAddItem = (short)SendMessage(hWndCtl, LB_GETCURSEL, 0, 0);
  412. BYTE nArrayID = (BYTE)SendMessage(hWndCtl, LB_GETITEMDATA, (WPARAM)iAddItem, 0);
  413. LPDIJOYTYPEINFO lpdiJoyInfo = new DIJOYTYPEINFO;
  414. ASSERT (lpdiJoyInfo);
  415. ZeroMemory(lpdiJoyInfo, sizeof(DIJOYTYPEINFO));
  416. lpdiJoyInfo->dwSize = sizeof(DIJOYTYPEINFO);
  417. DWORD dwFlags = DITC_REGHWSETTINGS;
  418. if( nGameportBus > 1 )
  419. dwFlags |= DITC_FLAGS1;
  420. VERIFY(SUCCEEDED(pDIJoyConfig->GetTypeInfo(pwszTypeArray[nArrayID], (LPDIJOYTYPEINFO)lpdiJoyInfo, dwFlags)));
  421. /*
  422. if (nGameportBus > 1)
  423. {
  424. HWND hCtrl = GetDlgItem(hDlg, IDC_GAMEPORTLIST);
  425. // Search for AutoDetect in the list!
  426. char nIndex = (char)::SendMessage(hCtrl, CB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)(LPCTSTR)lpszAutoDetect);
  427. // If it's got the JOYTYPE_NOAUTODETECTGAMEPORT flag, remove AutoDetect from the ListCtrl
  428. if (lpdiJoyInfo->dwFlags1 & JOYTYPE_NOAUTODETECTGAMEPORT)
  429. {
  430. // it could fail because the entry is not available...
  431. if (nIndex != CB_ERR)
  432. ::SendMessage(hCtrl, CB_DELETESTRING, (WPARAM)nIndex, 0);
  433. }
  434. // Otherwise, verify that AutoDetect is present... if not, add it!
  435. else
  436. {
  437. // it could fail because the entry is not available...
  438. if (nIndex == CB_ERR)
  439. ::SendMessage(hCtrl, CB_SETITEMDATA, ::SendMessage(hCtrl, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)lpszAutoDetect), AUTODETECT_PORT);
  440. }
  441. ::PostMessage(hCtrl, CB_SETCURSEL, (WPARAM)0, (LPARAM)0);
  442. }
  443. */
  444. PostDlgItemEnableWindow(hDlg, IDC_JOY1HASRUDDER, (lpdiJoyInfo->hws.dwFlags & JOY_HWS_HASR) ? FALSE : TRUE);
  445. if( lpdiJoyInfo )
  446. delete (lpdiJoyInfo);
  447. break;
  448. }
  449. if( code != LBN_DBLCLK )
  450. break;
  451. case IDOK:
  452. iAddItem = (short)SendDlgItemMessage(hDlg, IDC_DEVICE_LIST, LB_GETCURSEL, 0, 0);
  453. if( iAddItem == NO_ITEM )
  454. break;
  455. // Check to see if they have a GamePortList
  456. {
  457. HWND hCtrl = GetDlgItem(hDlg, IDC_GAMEPORTLIST);
  458. ASSERT (hCtrl);
  459. if( IsWindowVisible(hCtrl) )
  460. {
  461. // Check to see if the user has a port selected!
  462. if( SendMessage(hCtrl, CB_GETCURSEL, 0, 0) == CB_ERR )
  463. {
  464. // blj: TODO: Clear this message with UE
  465. Error((short)IDS_NO_GAMEPORT_TITLE, (short)IDS_NO_GAMEPORT);
  466. break;
  467. }
  468. }
  469. }
  470. iItem = 0;
  471. AddSelectedItem(hDlg);
  472. case IDCANCEL:
  473. EndDialog(hDlg, id);
  474. break;
  475. }
  476. }
  477. /// Custom Dialog procedure
  478. BOOL WINAPI CustomDialogProc(HWND hDlg, ULONG uMsg, WPARAM wParam, LPARAM lParam)
  479. {
  480. static LPWSTR lpwszVIDPID;
  481. switch( uMsg )
  482. {
  483. case WM_DESTROY:
  484. {
  485. HICON hIcon = (HICON)SendMessage(hDlg, WM_GETICON, (WPARAM)ICON_SMALL, 0);
  486. DestroyIcon(hIcon);
  487. }
  488. break;
  489. case WM_LBUTTONDOWN:
  490. // Click Drag service for PropSheets!
  491. PostMessage(hDlg, WM_NCLBUTTONDOWN, (WPARAM)HTCAPTION, lParam);
  492. break;
  493. case WM_HELP:
  494. OnHelp(lParam);
  495. return(1);
  496. case WM_CONTEXTMENU:
  497. OnContextMenu(wParam, lParam);
  498. return(TRUE);
  499. case WM_INITDIALOG:
  500. // Set up the Buttons and Axis combo boxs!
  501. {
  502. HICON hIcon = (HICON)LoadImage(ghInstance, MAKEINTRESOURCE(IDI_CPANEL), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE);
  503. ASSERT (hIcon);
  504. if( hIcon )
  505. ::PostMessage(hDlg, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)hIcon);
  506. // Return if no available VID/PIDs found!
  507. lpwszVIDPID = new (WCHAR[STR_LEN_32]);
  508. ASSERT (lpwszVIDPID);
  509. pDIJoyConfig->Acquire();
  510. if( !GetNextAvailableVIDPID(lpwszVIDPID) )
  511. {
  512. if( lpwszVIDPID )
  513. delete[] (lpwszVIDPID);
  514. EndDialog(hDlg, IDCANCEL);
  515. // Let the user know that they need to remove some "Custom" devices!
  516. Error((short)IDS_NO_NAME_TITLE, (short)IDS_NOAVAILABLEVIDPID );
  517. return(FALSE);
  518. }
  519. // init id list
  520. BYTE nButtons = MAX_ANALOG_BUTTONS;
  521. TCHAR szTmp[3];
  522. HWND hCtrl = GetDlgItem(hDlg, IDC_COMBO_BUTTONS);
  523. // Fill the Buttons combo...
  524. do
  525. {
  526. itoa(nButtons, (LPTSTR)&szTmp);
  527. SendMessage(hCtrl, CB_ADDSTRING, (WPARAM)0, (LPARAM)(LPCTSTR)szTmp);
  528. } while( nButtons-- );
  529. // Set Default to four buttons
  530. SendMessage(hCtrl, CB_SETCURSEL, MAX_ANALOG_BUTTONS, 0);
  531. // Use nButtons for Axis...
  532. nButtons = MAX_ANALOG_AXIS;
  533. hCtrl = GetDlgItem(hDlg, IDC_COMBO_AXIS);
  534. // Fill the Axis combo...
  535. do
  536. {
  537. itoa(nButtons--, (LPTSTR)&szTmp);
  538. SendMessage(hCtrl, CB_ADDSTRING, (WPARAM)0, (LPARAM)(LPCTSTR)szTmp);
  539. } while( nButtons > 1 );
  540. // Set Default to two Axis
  541. SendMessage(hCtrl, CB_SETCURSEL, 0, 0);
  542. }
  543. ::PostMessage(GetDlgItem(hDlg, IDC_SPECIAL_JOYSTICK), BM_SETCHECK, BST_CHECKED, 0);
  544. SendDlgItemMessage(hDlg, IDC_EDIT_NAME, EM_LIMITTEXT, (WPARAM)MAX_STR_LEN, 0);
  545. return(1);
  546. case WM_COMMAND:
  547. switch( LOWORD(wParam) )
  548. {
  549. case IDOK:
  550. {
  551. // defines for error states!
  552. #define DUPLICATE_NAME 0x01
  553. #define NO_NAME 0x02
  554. #define INVALID_NAME 0x04
  555. BYTE nLen = (BYTE)SendDlgItemMessage(hDlg, IDC_EDIT_NAME, EM_LINELENGTH, 0, 0);
  556. LPTSTR pszTypeName = NULL;
  557. if( nLen )
  558. {
  559. pszTypeName = new (TCHAR[nLen+1]);
  560. ASSERT (pszTypeName);
  561. // Get the Type/Display Name
  562. GetDlgItemText(hDlg, IDC_EDIT_NAME, (LPTSTR)pszTypeName, nLen+1);
  563. if( _tcschr(pszTypeName, TEXT('\\')) )
  564. nLen = INVALID_NAME;
  565. else
  566. {
  567. // Make sure it's not a duplicate!
  568. // start of fix #9269
  569. LPDIJOYTYPEINFO_DX5 lpdiGetJoyInfo = new DIJOYTYPEINFO_DX5;
  570. ASSERT (lpdiGetJoyInfo);
  571. ZeroMemory(lpdiGetJoyInfo, sizeof(DIJOYTYPEINFO_DX5));
  572. lpdiGetJoyInfo->dwSize = sizeof(DIJOYTYPEINFO_DX5);
  573. // Clean-up nLen!
  574. BYTE n = nLen = 0;
  575. // Search for a Duplicate Display Name!!!
  576. while( pwszTypeArray[n] )
  577. {
  578. if( FAILED(pDIJoyConfig->GetTypeInfo(pwszTypeArray[n++], (LPDIJOYTYPEINFO)lpdiGetJoyInfo, DITC_DISPLAYNAME)) )
  579. {
  580. TRACE(TEXT("JOY.CPL: ADD.CPP: GetTypeInfo Failed!\n"));
  581. continue;
  582. }
  583. #ifndef _UNICODE
  584. USES_CONVERSION;
  585. #endif
  586. if( _tcsncmp(pszTypeName,
  587. #ifdef _UNICODE
  588. lpdiGetJoyInfo->wszDisplayName,
  589. #else
  590. W2A(lpdiGetJoyInfo->wszDisplayName),
  591. #endif
  592. wcslen(lpdiGetJoyInfo->wszDisplayName)+1) == 0 )
  593. {
  594. nLen = DUPLICATE_NAME;
  595. break;
  596. }
  597. }
  598. if( lpdiGetJoyInfo ) {
  599. delete (lpdiGetJoyInfo);
  600. }
  601. // end of fix #9269
  602. }
  603. } else nLen = NO_NAME;
  604. // Check for an error!
  605. if( nLen )
  606. {
  607. if( pszTypeName )
  608. delete[] (pszTypeName);
  609. // Give the user the appropriate error!
  610. switch( nLen )
  611. {
  612. case DUPLICATE_NAME:
  613. Error((SHORT)IDS_NO_NAME_TITLE, (SHORT)IDS_DUPLICATE_TYPE);
  614. break;
  615. case NO_NAME:
  616. Error((short)IDS_NO_NAME_TITLE, (short)IDS_NO_NAME);
  617. break;
  618. case INVALID_NAME:
  619. Error((short)IDS_NO_NAME_TITLE, (short)IDS_INVALID_NAME);
  620. break;
  621. }
  622. // Set Focus to the Dialog
  623. SetFocus(hDlg);
  624. HWND hCtrl = GetDlgItem(hDlg, IDC_EDIT_NAME);
  625. ASSERT (hCtrl);
  626. // Set Focus to the Control
  627. SetFocus(hCtrl);
  628. // hilite the error
  629. PostMessage(hCtrl, EM_SETSEL, (WPARAM)0, (LPARAM)-1);
  630. return(FALSE);
  631. }
  632. // set the type information
  633. LPDIJOYTYPEINFO lpdiJoyInfo = new (DIJOYTYPEINFO);
  634. ASSERT (lpdiJoyInfo);
  635. ZeroMemory(lpdiJoyInfo, sizeof(DIJOYTYPEINFO));
  636. lpdiJoyInfo->dwSize = sizeof(DIJOYTYPEINFO);
  637. #ifndef _UNICODE
  638. USES_CONVERSION;
  639. #endif
  640. // Set the Display Name
  641. wcsncpy(lpdiJoyInfo->wszDisplayName,
  642. #ifdef _UNICODE
  643. pszTypeName,
  644. #else
  645. A2W(pszTypeName),
  646. #endif // _UNICODE
  647. lstrlen(pszTypeName)+1);
  648. if( pszTypeName )
  649. delete[] (pszTypeName);
  650. // Set the GUID - default to LegacyServer
  651. // Per Marcus, we don't want to do this anymore!
  652. //lpdiJoyInfo->clsidConfig = CLSID_LegacyServer;
  653. // Set the Hardware Settings
  654. lpdiJoyInfo->hws.dwNumButtons = (DWORD)SendDlgItemMessage(hDlg, IDC_COMBO_BUTTONS, CB_GETCURSEL, 0, 0);
  655. switch( SendDlgItemMessage(hDlg, IDC_COMBO_AXIS, CB_GETCURSEL, 0, 0) )
  656. {
  657. // R Axis
  658. case 1:
  659. // Check to see which button got checked...
  660. lpdiJoyInfo->hws.dwFlags |= ::SendMessage(GetDlgItem(hDlg, IDC_HASRUDDER), BM_GETCHECK, 0, 0) ? JOY_HWS_HASR : JOY_HWS_HASZ;
  661. break;
  662. // Z Axis
  663. case 2:
  664. lpdiJoyInfo->hws.dwFlags |= JOY_HWS_HASR;
  665. lpdiJoyInfo->hws.dwFlags |= JOY_HWS_HASZ;
  666. break;
  667. // X/Y are default!
  668. default:
  669. lpdiJoyInfo->hws.dwFlags = 0;
  670. break;
  671. }
  672. lpdiJoyInfo->hws.dwFlags |= ::SendMessage(GetDlgItem(hDlg, IDS_CUSTOM_HASPOV), BM_GETCHECK, 0, 0) ? JOY_HWS_HASPOV : 0;
  673. // Get Special char's status
  674. lpdiJoyInfo->hws.dwFlags |= ::SendMessage(GetDlgItem(hDlg, IDC_SPECIAL_JOYSTICK), BM_GETCHECK, 0, 0) ? 0
  675. : ::SendMessage(GetDlgItem(hDlg, IDC_SPECIAL_PAD), BM_GETCHECK, 0, 0) ? JOY_HWS_ISGAMEPAD
  676. : ::SendMessage(GetDlgItem(hDlg, IDC_SPECIAL_AUTO), BM_GETCHECK, 0, 0) ? JOY_HWS_ISCARCTRL
  677. : JOY_HWS_ISYOKE; // default to Yoke!
  678. // Set up wszHardwareId
  679. wcscpy(lpdiJoyInfo->wszHardwareId, L"GamePort\\");
  680. // This blocks the Huge DisplayName bug!
  681. // DINPUT change requires VID/PID at the end of the hardware ID... it was
  682. //StrNCatW(lpdiJoyInfo->wszHardwareId, lpwszVIDPID, 245);
  683. // Win95 does not like StrNCatW, we will use wcsncat
  684. wcsncat(lpdiJoyInfo->wszHardwareId, lpwszVIDPID, 245);
  685. if( SUCCEEDED(pDIJoyConfig->Acquire()) )
  686. {
  687. #ifdef _UNICODE
  688. if( FAILED(pDIJoyConfig->SetTypeInfo(lpwszVIDPID, lpdiJoyInfo, DITC_DISPLAYNAME | DITC_CLSIDCONFIG | DITC_REGHWSETTINGS | DITC_HARDWAREID)) )
  689. #else
  690. if( FAILED(pDIJoyConfig->SetTypeInfo(lpwszVIDPID, lpdiJoyInfo, DITC_DISPLAYNAME | DITC_CLSIDCONFIG | DITC_REGHWSETTINGS ) ) )
  691. #endif
  692. {
  693. #ifdef _DEBUG
  694. OutputDebugString(TEXT("JOY.CPL: ADD.CPP: CustomDlgProc: SetTypeInfo Failed!\n"));
  695. #endif
  696. }
  697. // Create the memory for the Custom device and stick it into the array!
  698. pwszTypeArray[nGamingDevices++] = _wcsdup(lpwszVIDPID);
  699. pDIJoyConfig->Unacquire();
  700. }
  701. if( lpdiJoyInfo ) delete (lpdiJoyInfo);
  702. }
  703. case IDCANCEL:
  704. if( lpwszVIDPID )
  705. delete[] (lpwszVIDPID);
  706. EndDialog(hDlg, LOWORD(wParam));
  707. break;
  708. case IDC_SPECIAL_JOYSTICK:
  709. case IDC_SPECIAL_YOKE:
  710. case IDC_SPECIAL_PAD:
  711. case IDC_SPECIAL_AUTO:
  712. CheckRadioButton(hDlg, IDC_SPECIAL_JOYSTICK, IDC_SPECIAL_AUTO, IDC_SPECIAL_JOYSTICK);
  713. break;
  714. case IDC_COMBO_AXIS:
  715. // Show/Hide IDC_HASRUDDER based on Selection of 3 Axis
  716. if( HIWORD(wParam) == CBN_SELCHANGE )
  717. {
  718. const USHORT nCtrlArray[] = {IDC_HASRUDDER, IDC_HASZAXIS};
  719. BYTE nCtrls = sizeof(nCtrlArray)/sizeof(short);
  720. // the '1' in the comparison is because the CB is Zero based!
  721. BOOL bShow = (BOOL)(SendDlgItemMessage(hDlg, IDC_COMBO_AXIS, CB_GETCURSEL, 0, 0) == 1);
  722. do
  723. {
  724. SetWindowPos( GetDlgItem(hDlg, nCtrlArray[--nCtrls]), NULL, NULL, NULL, NULL, NULL,
  725. SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | ((bShow) ? SWP_SHOWWINDOW : SWP_HIDEWINDOW));
  726. } while( nCtrls );
  727. if( bShow )
  728. ::PostMessage(GetDlgItem(hDlg, IDC_HASZAXIS), BM_SETCHECK, BST_CHECKED, 0);
  729. }
  730. break;
  731. }
  732. return(1);
  733. case WM_CLOSE:
  734. EndDialog(hDlg, 0);
  735. return(1);
  736. }
  737. return(0);
  738. }
  739. char GetNextAvailableID( void )
  740. {
  741. LPDIJOYCONFIG_DX5 pJoyConfig = new (DIJOYCONFIG_DX5);
  742. ASSERT (pJoyConfig);
  743. ZeroMemory(pJoyConfig, sizeof(DIJOYCONFIG_DX5));
  744. pJoyConfig->dwSize = sizeof (DIJOYCONFIG_DX5);
  745. char i = 0;
  746. do
  747. {
  748. switch( pDIJoyConfig->GetConfig(i, (LPDIJOYCONFIG)pJoyConfig, DIJC_REGHWCONFIGTYPE) )
  749. {
  750. case S_FALSE:
  751. case DIERR_NOMOREITEMS:
  752. case DIERR_NOTFOUND:
  753. case E_FAIL:
  754. goto EXIT;
  755. default:
  756. i++;
  757. break;
  758. }
  759. } while( i < NUMJOYDEVS );
  760. i = -1;
  761. // And it's Error time!
  762. Error((short)IDS_NO_IDS_TITLE, (short)IDS_NO_IDS);
  763. EXIT:
  764. if( pJoyConfig )
  765. delete (pJoyConfig);
  766. return(i);
  767. }
  768. ///////////////////////////////////////////////////////////////////////////////
  769. // FUNCTION: AddSelectedItem(HWND hDlg)
  770. //
  771. // PARAMETERS: hDlg - Handle to page
  772. //
  773. // PURPOSE: Adds selected item from List box.
  774. ///////////////////////////////////////////////////////////////////////////////
  775. char AddSelectedItem( HWND hDlg )
  776. {
  777. static BYTE n;
  778. DWORD dwFlags;
  779. HRESULT hr;
  780. int nID;
  781. #ifdef SUPPORT_TWO_2A2B
  782. BOOL f2_2A2B = FALSE;
  783. #endif
  784. nID = GetNextAvailableID();
  785. // GetNextAvailableID returns -1 if it fails!
  786. if( nID < 0 )
  787. return((char)nID);
  788. // Type info
  789. LPDIJOYTYPEINFO_DX5 lpdiJoyInfo = new (DIJOYTYPEINFO_DX5);
  790. ASSERT (lpdiJoyInfo);
  791. ZeroMemory(lpdiJoyInfo, sizeof(DIJOYTYPEINFO_DX5));
  792. lpdiJoyInfo->dwSize = sizeof(DIJOYTYPEINFO_DX5);
  793. BYTE nArrayID = (BYTE)SendDlgItemMessage(hDlg, IDC_DEVICE_LIST, LB_GETITEMDATA, (WPARAM)iAddItem, 0);
  794. VERIFY(SUCCEEDED(pDIJoyConfig->GetTypeInfo(pwszTypeArray[nArrayID], (LPDIJOYTYPEINFO)lpdiJoyInfo, DITC_REGHWSETTINGS | DITC_CALLOUT | DITC_DISPLAYNAME)));
  795. #ifdef SUPPORT_TWO_2A2B
  796. #ifndef _UNICODE
  797. if( wcscmp( pwszTypeArray[nArrayID], L"#<" ) == 0 ) {
  798. f2_2A2B = TRUE;
  799. lpdiJoyInfo->hws.dwFlags = 0;
  800. pwszTypeArray[nArrayID][1] = L'2';
  801. } else {
  802. f2_2A2B = FALSE;
  803. }
  804. #endif
  805. #endif
  806. LPDIJOYCONFIG pTempJoyConfig = new DIJOYCONFIG;
  807. ASSERT (pTempJoyConfig);
  808. ZeroMemory(pTempJoyConfig, sizeof(DIJOYCONFIG));
  809. pTempJoyConfig->dwSize = sizeof (DIJOYCONFIG);
  810. pTempJoyConfig->hwc.hws = lpdiJoyInfo->hws;
  811. pTempJoyConfig->hwc.hws.dwFlags |= JOY_HWS_ISANALOGPORTDRIVER;
  812. // Do the Rudder Flags!
  813. if( ::SendMessage(GetDlgItem(hDlg, IDC_JOY1HASRUDDER), BM_GETCHECK, 0, 0) )
  814. {
  815. pTempJoyConfig->hwc.hws.dwFlags |= JOY_HWS_HASR;
  816. pTempJoyConfig->hwc.dwUsageSettings |= JOY_US_HASRUDDER;
  817. }
  818. // set default to present
  819. pTempJoyConfig->hwc.dwUsageSettings |= JOY_US_PRESENT;
  820. pTempJoyConfig->hwc.dwType = nArrayID;
  821. wcsncpy(pTempJoyConfig->wszCallout, lpdiJoyInfo->wszCallout, wcslen(lpdiJoyInfo->wszCallout)+1);
  822. wcsncpy(pTempJoyConfig->wszType, pwszTypeArray[nArrayID], wcslen(pwszTypeArray[nArrayID])+1);
  823. LPWSTR lpszPortName = NULL;
  824. if( SUCCEEDED(pDIJoyConfig->Acquire()) )
  825. {
  826. // This stops Memphis and gameport-less systems!!!
  827. if( nGameportBus )
  828. {
  829. // no point asking the Combo box if there's really no choice!
  830. if( nGameportBus > 1 )
  831. {
  832. n = (BYTE)SendDlgItemMessage(hDlg, IDC_GAMEPORTLIST, CB_GETITEMDATA,
  833. (WPARAM)SendDlgItemMessage(hDlg, IDC_GAMEPORTLIST, CB_GETCURSEL, 0, 0), 0);
  834. } else
  835. {
  836. n = 0;
  837. }
  838. if( n == AUTODETECT_PORT )
  839. {
  840. #ifdef _DEBUG
  841. OutputDebugString(TEXT("JOY.CPL: ADD.CPP: Selected Port is AutoDetect!\n"));
  842. #endif
  843. pTempJoyConfig->guidGameport = GUID_GAMEENUM_BUS_ENUMERATOR;
  844. } else
  845. {
  846. // Zero the memory because the buffer still contains the old data!!!
  847. ZeroMemory(lpdiJoyInfo, sizeof(DIJOYTYPEINFO_DX5));
  848. lpdiJoyInfo->dwSize = sizeof(DIJOYTYPEINFO_DX5);
  849. #ifdef _DEBUG
  850. TRACE(TEXT("JOY.CPL: ADD.CPP: Port List index is %d or %s!\n"), n, pwszGameportBus[n]);
  851. #endif
  852. if( SUCCEEDED(pDIJoyConfig->GetTypeInfo(pwszGameportBus[n], (LPDIJOYTYPEINFO)lpdiJoyInfo, DITC_CLSIDCONFIG | DITC_DISPLAYNAME)) )
  853. {
  854. pTempJoyConfig->guidGameport = lpdiJoyInfo->clsidConfig;
  855. lpszPortName = _wcsdup(lpdiJoyInfo->wszDisplayName);
  856. }
  857. }
  858. }
  859. // This is for Memphis and odd case NT systems!
  860. if( pTempJoyConfig->guidGameport == GUID_NULL )
  861. {
  862. pTempJoyConfig->guidGameport = GUID_GAMEENUM_BUS_ENUMERATOR;
  863. #ifdef _DEBUG
  864. OutputDebugString(TEXT("JOY.CPL: ADD.CPP: Selected Port did not return a clsidConfig so AutoDetect is being used!\n"));
  865. #endif
  866. }
  867. // Set the hour glass
  868. SetCursor(LoadCursor(NULL, IDC_WAIT));
  869. // ISSUE-2001/03/29-timgill (MarcAnd) Why would we want to block updates when we're adding a device?
  870. #if 1
  871. // Unblock the WM_DEVICECHANGE message handler!
  872. nFlags &= ~BLOCK_UPDATE;
  873. nFlags |= ON_PAGE;
  874. /*
  875. * Set the nReEnum counter going so that for the next n WM_TIMER
  876. * messages (or until the device arrives) we can consider
  877. * doing a refresh.
  878. * The value is somewhat arbitrary.
  879. */
  880. nReEnum = 43;
  881. /*
  882. * Set a target for the number of devices so that the extra
  883. * reenumerations can be avoided if this target is reached.
  884. */
  885. nTargetAssigned = nAssigned+1;
  886. #else
  887. nFlags |= BLOCK_UPDATE;
  888. #endif
  889. dwFlags = DIJC_REGHWCONFIGTYPE | DIJC_CALLOUT;
  890. dwFlags |= ::SendDlgItemMessage(hDlg, IDC_WDM, BM_GETCHECK, 0, 0) ? DIJC_WDMGAMEPORT : 0;
  891. if( FAILED(hr = pDIJoyConfig->SetConfig(nID, pTempJoyConfig, dwFlags)) )
  892. {
  893. // Let the user know what happend!
  894. if( hr == E_ACCESSDENIED )
  895. {
  896. // Let the use know that the port is already occupied and that they need to remove that device or
  897. // re-assign the device to an unoccupied port.
  898. LPDIJOYCONFIG lpJoyCfg = new (DIJOYCONFIG);
  899. ASSERT (lpJoyCfg);
  900. ZeroMemory(lpJoyCfg, sizeof(DIJOYCONFIG));
  901. lpJoyCfg->dwSize = sizeof(DIJOYCONFIG);
  902. // Cycle threw pAssigned and find the device with the same port name!
  903. BYTE nIndex = nAssigned;
  904. do
  905. {
  906. if( SUCCEEDED(pDIJoyConfig->GetConfig(pAssigned[--nIndex]->ID, lpJoyCfg, DIJC_WDMGAMEPORT)) )
  907. {
  908. if( lpJoyCfg->guidGameport == pTempJoyConfig->guidGameport )
  909. break;
  910. }
  911. } while( nIndex );
  912. if( lpJoyCfg )
  913. delete (lpJoyCfg);
  914. DIPROPSTRING *pDIPropStr = new (DIPROPSTRING);
  915. ASSERT (pDIPropStr);
  916. ZeroMemory(pDIPropStr, sizeof(DIPROPSTRING));
  917. pDIPropStr->diph.dwSize = sizeof(DIPROPSTRING);
  918. pDIPropStr->diph.dwHeaderSize = sizeof(DIPROPHEADER);
  919. pDIPropStr->diph.dwHow = DIPH_DEVICE;
  920. // Ok now.. you found it... use the Device pointer to get it's Friendly name!
  921. if( SUCCEEDED(pAssigned[nIndex]->fnDeviceInterface->GetProperty(DIPROP_INSTANCENAME, &pDIPropStr->diph)) )
  922. {
  923. // Put ellipse in text to avoid buffer over-flow.
  924. // Limit displayed name to 50 chars... not completely arbitrary,
  925. // we need to leave room in the Message string...
  926. // who knows how long the string will get when translated!
  927. if( wcslen(pDIPropStr->wsz) > 50 )
  928. {
  929. pDIPropStr->wsz[47] = pDIPropStr->wsz[48] = pDIPropStr->wsz[49] = L'.';
  930. pDIPropStr->wsz[50] = L'\0';
  931. }
  932. LPTSTR lptszMsgFormat = new (TCHAR[MAX_STR_LEN]);
  933. ASSERT (lptszMsgFormat);
  934. VERIFY(LoadString(ghInstance, IDS_ADD_PORT_MSGFORMAT, lptszMsgFormat, MAX_STR_LEN));
  935. LPTSTR lptszMsg = new (TCHAR[MAX_STR_LEN]);
  936. ASSERT (lptszMsg);
  937. // Format the message
  938. wsprintf(lptszMsg, lptszMsgFormat, pDIPropStr->wsz, lpszPortName, pAssigned[nIndex]->ID+1);
  939. VERIFY(LoadString(ghInstance, IDS_ADD_PORT_OCCUPIED, lptszMsgFormat, MAX_STR_LEN));
  940. MessageBox(hDlg, lptszMsg, lptszMsgFormat, MB_ICONHAND | MB_OK | MB_APPLMODAL);
  941. if( lptszMsgFormat )
  942. delete[] (lptszMsgFormat);
  943. if( lptszMsg )
  944. delete[] (lptszMsg);
  945. }
  946. if( pDIPropStr )
  947. delete (pDIPropStr);
  948. } else if( hr == DIERR_DEVICEFULL )
  949. {
  950. Error((short)IDS_GAMEPORT_OCCUPIED_TITLE, (short)IDS_GAMEPORT_OCCUPIED);
  951. } else
  952. {
  953. // Something Ugly happened!
  954. Error((short)IDS_NO_GAMENUM_TITLE, (short)IDS_NO_GAMENUM);
  955. }
  956. } else
  957. {
  958. #ifdef _UNICODE
  959. // Fix #55524
  960. if( SUCCEEDED(pDIJoyConfig->GetConfig(nID, pTempJoyConfig, DIJC_REGHWCONFIGTYPE)) )
  961. {
  962. if( !(pTempJoyConfig->hwc.dwUsageSettings & JOY_US_PRESENT) )
  963. {
  964. pTempJoyConfig->hwc.dwUsageSettings |= JOY_US_PRESENT;
  965. pTempJoyConfig->hwc.hwv.dwCalFlags |= 0x80000000;
  966. pTempJoyConfig->hwc.hws.dwFlags |= JOY_HWS_ISANALOGPORTDRIVER;
  967. VERIFY(SUCCEEDED(pDIJoyConfig->SetConfig(nID, pTempJoyConfig, DIJC_REGHWCONFIGTYPE)));
  968. }
  969. }
  970. // end of Fix #55524
  971. #endif
  972. // make sure VJOYD is notified
  973. if( !(nFlags & ON_NT) ) {
  974. pDIJoyConfig->SendNotify();
  975. Sleep(10);
  976. pDIJoyConfig->SendNotify();
  977. }
  978. #ifndef _UNICODE
  979. #ifdef SUPPORT_TWO_2A2B
  980. /*
  981. * Add the other part of Two_2Axis_2Button joystick.
  982. */
  983. if( f2_2A2B ) {
  984. nID = GetNextAvailableID();
  985. if( nID >= 0 ){
  986. hr = pDIJoyConfig->SetConfig(nID, pTempJoyConfig, dwFlags);
  987. if( SUCCEEDED(hr) ) {
  988. if( !(nFlags & ON_NT) )
  989. pDIJoyConfig->SendNotify();
  990. }
  991. }
  992. }
  993. #endif
  994. #endif
  995. }
  996. if( lpszPortName )
  997. free(lpszPortName);
  998. // Set the standard pointer
  999. SetCursor(LoadCursor(NULL, IDC_ARROW));
  1000. pDIJoyConfig->Unacquire();
  1001. }
  1002. if( lpdiJoyInfo )
  1003. delete (lpdiJoyInfo);
  1004. if( pTempJoyConfig )
  1005. delete (pTempJoyConfig);
  1006. return((char)nID);
  1007. }
  1008. BOOL UpdateListCtrl( HWND hCtrl )
  1009. {
  1010. // Turn Redraw off here else it will flicker!
  1011. ::SendMessage(hCtrl, WM_SETREDRAW, (WPARAM)FALSE, 0);
  1012. // delete all existing entries
  1013. ::SendMessage(hCtrl, LB_RESETCONTENT, 0, 0);
  1014. // Type info
  1015. LPDIJOYTYPEINFO_DX5 lpdiJoyInfo = new (DIJOYTYPEINFO_DX5);
  1016. ASSERT (lpdiJoyInfo);
  1017. ZeroMemory(lpdiJoyInfo, sizeof(DIJOYTYPEINFO_DX5));
  1018. lpdiJoyInfo->dwSize = sizeof(DIJOYTYPEINFO_DX5);
  1019. #ifndef _UNICODE
  1020. USES_CONVERSION;
  1021. #endif
  1022. BYTE nIndex = nGamingDevices-1;
  1023. ::SendMessage(hCtrl, LB_SETCOUNT, (WPARAM)(int)nIndex, 0);
  1024. LPWSTR lpStr = new WCHAR[MAX_STR_LEN];
  1025. ASSERT (lpStr);
  1026. BYTE nLargestStringLen = 0;
  1027. do
  1028. {
  1029. if( SUCCEEDED(pDIJoyConfig->GetTypeInfo(pwszTypeArray[nIndex], (LPDIJOYTYPEINFO)lpdiJoyInfo, DITC_DISPLAYNAME)) )
  1030. {
  1031. #ifdef _UNICODE
  1032. ::SendMessage(hCtrl, LB_SETITEMDATA,
  1033. (WPARAM)::SendMessage(hCtrl, LB_ADDSTRING, 0, (LPARAM)(LPCTSTR)lpdiJoyInfo->wszDisplayName), (LPARAM)nIndex);
  1034. #else
  1035. ::SendMessage(hCtrl, LB_SETITEMDATA,
  1036. (WPARAM)::SendMessage(hCtrl, LB_ADDSTRING, 0, (LPARAM)(LPCTSTR)W2A(lpdiJoyInfo->wszDisplayName)), (LPARAM)nIndex);
  1037. #endif
  1038. if( wcslen(lpdiJoyInfo->wszDisplayName) > nLargestStringLen )
  1039. {
  1040. nLargestStringLen = (BYTE)wcslen(lpdiJoyInfo->wszDisplayName);
  1041. wcscpy(lpStr, lpdiJoyInfo->wszDisplayName);
  1042. }
  1043. }
  1044. } while( nIndex-- );
  1045. if( lpdiJoyInfo )
  1046. delete (lpdiJoyInfo);
  1047. #ifdef _UNICODE
  1048. PostHScrollBar(hCtrl, lpStr, nLargestStringLen);
  1049. #else
  1050. PostHScrollBar(hCtrl, W2A(lpStr), nLargestStringLen);
  1051. #endif
  1052. if( lpStr )
  1053. delete[] (lpStr);
  1054. // Select the default selection to the 0th device type
  1055. iAddItem = 0;
  1056. ::PostMessage(hCtrl, LB_SETCURSEL, (WPARAM)iAddItem, 0);
  1057. // Turn the redraw flag back on!
  1058. ::SendMessage (hCtrl, WM_SETREDRAW, (WPARAM)TRUE, 0);
  1059. InvalidateRect(hCtrl, NULL, TRUE);
  1060. return(TRUE);
  1061. }
  1062. // Please check to see if nGameportBus is > 0 before a call to this function!
  1063. // It will work, but What a waste!
  1064. BOOL PopulatePortList( HWND hCtrl )
  1065. {
  1066. if( !::IsWindow(hCtrl) )
  1067. {
  1068. TRACE(TEXT("JOY.CPL: PopulatePortList: HWND passed to PopulatePortList is NOT a valid Window!\n"));
  1069. return(FALSE);
  1070. }
  1071. SendMessage(hCtrl, CB_SETEXTENDEDUI, TRUE, 0);
  1072. // temp so we don't damage the global!
  1073. BYTE n = nGameportBus;
  1074. LPDIJOYTYPEINFO lpDIJoyTypeInfo = new (DIJOYTYPEINFO);
  1075. ASSERT(lpDIJoyTypeInfo);
  1076. #ifndef _UNICODE
  1077. USES_CONVERSION;
  1078. #endif
  1079. lpDIJoyTypeInfo->dwSize = sizeof(DIJOYTYPEINFO);
  1080. // Populate the list as they were enumerated.
  1081. do
  1082. {
  1083. if( FAILED(pDIJoyConfig->GetTypeInfo(pwszGameportBus[--n], lpDIJoyTypeInfo, DITC_DISPLAYNAME)) )
  1084. {
  1085. TRACE(TEXT("JOY.CPL: ADD.CPP: GetTypeInfo failed!\n"));
  1086. continue;
  1087. }
  1088. // put the name in the list and place the index of the port array
  1089. // in it's item data...
  1090. SendMessage(hCtrl, CB_SETITEMDATA,
  1091. #ifdef _UNICODE
  1092. SendMessage(hCtrl, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)lpDIJoyTypeInfo->wszDisplayName), n);
  1093. #else
  1094. SendMessage(hCtrl, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)W2A(lpDIJoyTypeInfo->wszDisplayName)), n);
  1095. #endif
  1096. // Just in case you're curious, we're going backwards so the default
  1097. // port is the lowest available one.
  1098. } while( n );
  1099. // Don't forget Auto-Detect!
  1100. // But only if there's more than one port!
  1101. ::SendMessage(hCtrl, CB_SETITEMDATA, ::SendMessage(hCtrl, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)lpszAutoDetect), AUTODETECT_PORT);
  1102. // While you're at it, check to see if one is available...
  1103. // if so, put it as the default!
  1104. ::PostMessage(hCtrl, CB_SETCURSEL, (WPARAM)0, (LPARAM)0);
  1105. if( lpDIJoyTypeInfo )
  1106. delete (lpDIJoyTypeInfo);
  1107. return(TRUE);
  1108. }
  1109. static BOOL IsTypeActive( short *nArrayIndex )
  1110. {
  1111. if( *nArrayIndex > nGamingDevices )
  1112. {
  1113. #ifdef _DEBUG
  1114. OutputDebugString(TEXT("JOY.CPL: IsTypeActive: nArrayIndex > nGamingDevices!\n"));
  1115. #endif
  1116. return(FALSE);
  1117. }
  1118. BOOL bRet = FALSE;
  1119. BYTE nIndex = nAssigned;
  1120. BYTE nStrLen = (BYTE)wcslen(pwszTypeArray[*nArrayIndex])+1;
  1121. LPDIJOYCONFIG_DX5 lpDIJoyConfig = new (DIJOYCONFIG_DX5);
  1122. ASSERT (lpDIJoyConfig);
  1123. ZeroMemory(lpDIJoyConfig, sizeof(DIJOYCONFIG_DX5));
  1124. lpDIJoyConfig->dwSize = sizeof (DIJOYCONFIG_DX5);
  1125. // find the assigned ID's
  1126. while( nIndex-- )
  1127. {
  1128. if( SUCCEEDED(pDIJoyConfig->GetConfig(pAssigned[nIndex]->ID, (LPDIJOYCONFIG)lpDIJoyConfig, DIJC_REGHWCONFIGTYPE)) )
  1129. {
  1130. // if you find it... break out!
  1131. if( wcsncmp(lpDIJoyConfig->wszType, pwszTypeArray[*nArrayIndex], nStrLen) == 0 )
  1132. {
  1133. bRet = TRUE;
  1134. *nArrayIndex = nIndex;
  1135. break;
  1136. }
  1137. }
  1138. }
  1139. if( lpDIJoyConfig )
  1140. delete (lpDIJoyConfig);
  1141. return(bRet);
  1142. }
  1143. BOOL GetNextAvailableVIDPID(LPWSTR lpwszType )
  1144. {
  1145. // Make the VID/PID to compare from the following formula
  1146. // VID_045e&PID_100+JOY_HW_LASTENTRY to 100+JOY_HW_LASTENTRY+0xf
  1147. HKEY hKey;
  1148. BYTE n = JOY_HW_LASTENTRY;
  1149. wcsncpy(lpwszType, L"VID_045E&PID_0100", 18);
  1150. const WCHAR wszLookup[] = L"0123456789ABCDEF";
  1151. do
  1152. {
  1153. if( n < 0x10 )
  1154. {
  1155. lpwszType[16] = wszLookup[n];
  1156. } else
  1157. {
  1158. lpwszType[15] = wszLookup[1];
  1159. lpwszType[16] = wszLookup[n%0x10];
  1160. }
  1161. n++;
  1162. if( FAILED(pDIJoyConfig->OpenTypeKey(lpwszType, KEY_READ, &hKey)) )
  1163. break;
  1164. RegCloseKey(hKey);
  1165. } while( n < (JOY_HW_LASTENTRY+0x11) );
  1166. return(BOOL)(n < 0x1d);
  1167. }
  1168. //
  1169. // PostDlgItemEnableWindow(HWND hDlg, USHORT nItem, BOOL bEnabled)
  1170. //
  1171. void PostDlgItemEnableWindow(HWND hDlg, USHORT nItem, BOOL bEnabled)
  1172. {
  1173. HWND hCtrl = GetDlgItem(hDlg, nItem);
  1174. if( hCtrl )
  1175. PostEnableWindow(hCtrl, bEnabled);
  1176. }
  1177. //
  1178. // PostEnableWindow(HWND hCtrl, BOOL bEnabled)
  1179. //
  1180. void PostEnableWindow(HWND hCtrl, BOOL bEnabled)
  1181. {
  1182. DWORD dwStyle = GetWindowLong(hCtrl, GWL_STYLE);
  1183. // No point Redrawing the Window if there's no change!
  1184. if( bEnabled )
  1185. {
  1186. if( dwStyle & WS_DISABLED )
  1187. dwStyle &= ~WS_DISABLED;
  1188. else return;
  1189. } else
  1190. {
  1191. if( !(dwStyle & WS_DISABLED) )
  1192. dwStyle |= WS_DISABLED;
  1193. else return;
  1194. }
  1195. SetWindowLong(hCtrl, GWL_STYLE, dwStyle);
  1196. RedrawWindow(hCtrl, NULL, NULL, RDW_INTERNALPAINT | RDW_INVALIDATE);
  1197. }
  1198. /*
  1199. BOOL IsCustomType(BYTE nIndex)
  1200. {
  1201. BOOL bRet = FALSE;
  1202. // First verify VID is 045E
  1203. WCHAR *pwStr = StrStrW(pwszTypeArray[nIndex],L"VID_");
  1204. if (pwStr)
  1205. {
  1206. // Increment the pointer over the VID_ and test for 045E
  1207. pwStr = &pwStr[4];
  1208. if (_wcsnicmp(pwStr, L"045e", 4) == 0)
  1209. {
  1210. OutputDebugString(TEXT("Hit \n"));
  1211. // Now, increment the pointer over 045e and &PID_ and test for the range!
  1212. pwStr = &pwStr[9];
  1213. // Second, verify PID is between 0x100 + JOY_HW_LASTENTRY and
  1214. // 0x100 + JOY_HW_LASTENTRY + 0xf
  1215. bRet = TRUE;
  1216. }
  1217. }
  1218. return bRet;
  1219. }
  1220. */
  1221. void PostHScrollBar(HWND hCtrl, LPCTSTR lpStr, BYTE nStrLen)
  1222. {
  1223. SIZE sz;
  1224. HDC hDC = GetWindowDC(hCtrl);
  1225. if( hDC != NULL ) /* PREFIX MANBUGS: 29336*/
  1226. {
  1227. GetTextExtentPoint32(hDC, lpStr, nStrLen, &sz);
  1228. ReleaseDC(hCtrl, hDC);
  1229. ::PostMessage(hCtrl, LB_SETHORIZONTALEXTENT, (WPARAM)sz.cx, 0);
  1230. }
  1231. }