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.

822 lines
21 KiB

  1. /******************************************************************************
  2. * File: CDeviceUI.cpp
  3. *
  4. * Desc:
  5. *
  6. * CDeviceUI is a helper that holds all the views and a bunch of
  7. * information for a specific device. It has a CFlexWnd whose
  8. * handler it sets to the CDeviceView for the current view,
  9. * thus reusing one window to implement multiple pages.
  10. *
  11. * All CDeviceViews and CDeviceControls have a reference to the CDeviceUI
  12. * that created them (m_ui). Thus, they also have access to the
  13. * CUIGlobals, since CDeviceUI has a reference to them (m_ui.m_uig).
  14. * CDeviceUI also provides the following read-only public variables
  15. * for convenience, all referring to the device this CDeviceUI
  16. * represents:
  17. *
  18. * const DIDEVICEINSTANCEW &m_didi;
  19. * const LPDIRECTINPUTDEVICE8W &m_lpDID;
  20. * const DIDEVOBJSTRUCT &m_os;
  21. *
  22. * See usefuldi.h for a description of DIDEVOBJSTRUCT.
  23. *
  24. * CDeviceUI communicates to the rest of the UI via the CDeviceUINotify
  25. * abstract base class. Another class (in our case CDIDeviceActionConfigPage)
  26. * must derive from CDeviceUINotify, and define the DeviceUINotify() and
  27. * IsControlMapped() virtual functions. This derived class must be passed as
  28. * the last parameter to CDeviceUI's Init() function. All the views and
  29. * controls within the views notify the UI of user actions via m_ui.Notify(),
  30. * so that all actionformat manipulation can be done in the page class. The
  31. * views and controls themselves never touch the actionformat. See the
  32. * DEVICEUINOTIFY structure below for information on the parameter passed
  33. * through Notify()/DeviceUINotify().
  34. *
  35. * Copyright (C) 1999-2000 Microsoft Corporation. All Rights Reserved.
  36. *
  37. ***************************************************************************/
  38. #include "common.hpp"
  39. #include <dinputd.h>
  40. //@@BEGIN_MSINTERNAL
  41. #ifdef DDKBUILD
  42. #include <initguid.h>
  43. #include "..\dx8\dimap\dimap.h"
  44. #endif
  45. //@@END_MSINTERNAL
  46. #include "configwnd.h"
  47. #define DIPROP_MAPFILE MAKEDIPROP(0xFFFD)
  48. CDeviceUI::CDeviceUI(CUIGlobals &uig, IDIConfigUIFrameWindow &uif) :
  49. m_uig(uig), m_UIFrame(uif),
  50. m_didi(m_priv_didi), m_lpDID(m_priv_lpDID), m_os(m_priv_os),
  51. m_pCurView(NULL),
  52. m_pNotify(NULL), m_hWnd(NULL), m_bInEditMode(FALSE)
  53. {
  54. m_priv_lpDID = NULL;
  55. }
  56. CDeviceUI::~CDeviceUI()
  57. {
  58. Unpopulate();
  59. }
  60. HRESULT CDeviceUI::Init(const DIDEVICEINSTANCEW &didi, LPDIRECTINPUTDEVICE8W lpDID, HWND hWnd, CDeviceUINotify *pNotify)
  61. {tracescope(__ts, _T("CDeviceUI::Init()...\n"));
  62. // save the params
  63. m_priv_didi = didi;
  64. m_priv_lpDID = lpDID;
  65. m_pNotify = pNotify;
  66. m_hWnd = hWnd;
  67. // fail if we don't have lpDID
  68. if (m_lpDID == NULL)
  69. {
  70. etrace(_T("CDeviceUI::Init() was passed a NULL lpDID!\n"));
  71. return E_FAIL;
  72. }
  73. // fill the devobjstruct
  74. HRESULT hr = FillDIDeviceObjectStruct(m_priv_os, lpDID);
  75. if (FAILED(hr))
  76. {
  77. etrace1(_T("FillDIDeviceObjectStruct() failed, returning 0x%08x\n"), hr);
  78. return hr;
  79. }
  80. // view rect needs to be set before populating so the views are
  81. // created with the correct dimensions
  82. m_ViewRect = g_ViewRect;
  83. // populate
  84. hr = PopulateAppropriately(*this);
  85. if (FAILED(hr))
  86. return hr;
  87. // if there are no views, return
  88. if (GetNumViews() < 1)
  89. {
  90. //@@BEGIN_MSINTERNAL
  91. // should be unnecessary, but wtheck...
  92. //@@END_MSINTERNAL
  93. Unpopulate();
  94. return E_FAIL;
  95. }
  96. // show the first view
  97. SetView(0);
  98. return hr;
  99. }
  100. void CDeviceUI::Unpopulate()
  101. {
  102. m_pCurView = NULL;
  103. for (int i = 0; i < GetNumViews(); i++)
  104. {
  105. if (m_arpView[i] != NULL)
  106. delete m_arpView[i];
  107. m_arpView[i] = NULL;
  108. }
  109. m_arpView.RemoveAll();
  110. Invalidate();
  111. }
  112. void CDeviceUI::SetView(int nView)
  113. {
  114. if (nView >= 0 && nView < GetNumViews())
  115. SetView(m_arpView[nView]);
  116. }
  117. void CDeviceUI::SetView(CDeviceView *pView)
  118. {
  119. if (m_pCurView != NULL)
  120. ShowWindow(m_pCurView->m_hWnd, SW_HIDE);
  121. m_pCurView = pView;
  122. if (m_pCurView != NULL)
  123. ShowWindow(m_pCurView->m_hWnd, SW_SHOW);
  124. }
  125. CDeviceView *CDeviceUI::GetView(int nView)
  126. {
  127. if (nView >= 0 && nView < GetNumViews())
  128. return m_arpView[nView];
  129. else
  130. return NULL;
  131. }
  132. CDeviceView *CDeviceUI::GetCurView()
  133. {
  134. return m_pCurView;
  135. }
  136. int CDeviceUI::GetViewIndex(CDeviceView *pView)
  137. {
  138. if (GetNumViews() == 0)
  139. return -1;
  140. for (int i = 0; i < GetNumViews(); i++)
  141. if (m_arpView[i] == pView)
  142. return i;
  143. return -1;
  144. }
  145. int CDeviceUI::GetCurViewIndex()
  146. {
  147. return GetViewIndex(m_pCurView);
  148. }
  149. // gets the thumbnail for the specified view,
  150. // using the selected version if the view is selected
  151. CBitmap *CDeviceUI::GetViewThumbnail(int nView)
  152. {
  153. return GetViewThumbnail(nView, GetView(nView) == GetCurView());
  154. }
  155. // gets the thumbnail for the specified view,
  156. // specifiying whether or not we want the selected version
  157. CBitmap *CDeviceUI::GetViewThumbnail(int nView, BOOL bSelected)
  158. {
  159. CDeviceView *pView = GetView(nView);
  160. if (pView == NULL)
  161. return NULL;
  162. return pView->GetImage(bSelected ? DVI_SELTHUMB : DVI_THUMB);
  163. }
  164. void CDeviceUI::DoForAllControls(DEVCTRLCALLBACK callback, LPVOID pVoid, BOOL bFixed)
  165. {
  166. int nv = GetNumViews();
  167. for (int v = 0; v < nv; v++)
  168. {
  169. CDeviceView *pView = GetView(v);
  170. if (pView == NULL)
  171. continue;
  172. int nc = pView->GetNumControls();
  173. for (int c = 0; c < nc; c++)
  174. {
  175. CDeviceControl *pControl = pView->GetControl(c);
  176. if (pControl == NULL)
  177. continue;
  178. callback(pControl, pVoid, bFixed);
  179. }
  180. }
  181. }
  182. typedef struct _DFCIAO {
  183. DWORD dwOffset;
  184. DEVCTRLCALLBACK callback;
  185. LPVOID pVoid;
  186. } DFCIAO;
  187. void DoForControlIfAtOffset(CDeviceControl *pControl, LPVOID pVoid, BOOL bFixed)
  188. {
  189. DFCIAO &dfciao = *((DFCIAO *)pVoid);
  190. if (pControl->GetOffset() == dfciao.dwOffset)
  191. dfciao.callback(pControl, dfciao.pVoid, bFixed);
  192. }
  193. void CDeviceUI::DoForAllControlsAtOffset(DWORD dwOffset, DEVCTRLCALLBACK callback, LPVOID pVoid, BOOL bFixed)
  194. {
  195. DFCIAO dfciao;
  196. dfciao.dwOffset = dwOffset;
  197. dfciao.callback = callback;
  198. dfciao.pVoid = pVoid;
  199. DoForAllControls(DoForControlIfAtOffset, &dfciao, bFixed);
  200. }
  201. void SetControlCaptionTo(CDeviceControl *pControl, LPVOID pVoid, BOOL bFixed)
  202. {
  203. pControl->SetCaption((LPCTSTR)pVoid, bFixed);
  204. }
  205. void CDeviceUI::SetAllControlCaptionsTo(LPCTSTR tszCaption)
  206. {
  207. DoForAllControls(SetControlCaptionTo, (LPVOID)tszCaption);
  208. }
  209. void CDeviceUI::SetCaptionForControlsAtOffset(DWORD dwOffset, LPCTSTR tszCaption, BOOL bFixed)
  210. {
  211. DoForAllControlsAtOffset(dwOffset, SetControlCaptionTo, (LPVOID)tszCaption, bFixed);
  212. }
  213. void CDeviceUI::Invalidate()
  214. {
  215. if (m_pCurView != NULL)
  216. m_pCurView->Invalidate();
  217. }
  218. void CDeviceUI::SetEditMode(BOOL bEdit)
  219. {
  220. if (bEdit == m_bInEditMode)
  221. return;
  222. m_bInEditMode = bEdit;
  223. Invalidate();
  224. }
  225. //@@BEGIN_MSINTERNAL
  226. #ifdef DDKBUILD
  227. BOOL CDeviceUI::WriteToINI()
  228. {
  229. // JACK: do not remove this
  230. class dumpandcleardeletenotes {
  231. public:
  232. dumpandcleardeletenotes(CDeviceUI &ui) : bFailed(FALSE), m_ui(ui) {m_ui.DumpDeleteNotes();}
  233. ~dumpandcleardeletenotes() {if (!bFailed) m_ui.ClearDeleteNotes();}
  234. void SetFailed() {bFailed = TRUE;}
  235. private:
  236. BOOL bFailed;
  237. CDeviceUI &m_ui;
  238. } ___dacdn(*this);
  239. int failure__ids;
  240. BOOL bFailed = FALSE;
  241. #define FAILURE(ids) {___dacdn.SetFailed(); failure__ids = ids; bFailed = TRUE; goto cleanup;}
  242. HINSTANCE hInst = NULL;
  243. LPFNGETCLASSOBJECT fpClassFactory = NULL;
  244. LPDIRECTINPUTMAPPERVENDORW lpDiMap = NULL;
  245. IClassFactory *pDiMapCF = NULL;
  246. // Writes the callout information to INI file
  247. // Get INI path first
  248. HRESULT hr;
  249. TCHAR szIniPath[MAX_PATH];
  250. DIPROPSTRING dips;
  251. LPDIRECTINPUT8 lpDI = NULL;
  252. LPDIRECTINPUTDEVICE8 lpDID = NULL;
  253. GUID guid;
  254. BOOL bUsedDefault;
  255. int r;
  256. DWORD dwError;
  257. DWORD diver = DIRECTINPUT_VERSION;
  258. DIDEVICEIMAGEINFOW *pDelImgInfo = NULL;
  259. hr = DirectInput8Create(g_hModule, diver, IID_IDirectInput8, (LPVOID*)&lpDI, NULL);
  260. if (FAILED(hr))
  261. FAILURE(IDS_DICREATEFAILED);
  262. GetDeviceInstanceGuid(guid);
  263. hr = lpDI->CreateDevice(guid, &lpDID, NULL);
  264. if (FAILED(hr))
  265. FAILURE(IDS_CREATEDEVICEFAILED);
  266. // Check device type. If this is keyboard or mouse, don't need to saving anything.
  267. if ((m_priv_didi.dwDevType & 0xFF) == DI8DEVTYPE_KEYBOARD ||
  268. (m_priv_didi.dwDevType & 0xFF) == DI8DEVTYPE_MOUSE)
  269. FAILURE(0); // Fail silently. Do not display any error dialog
  270. ZeroMemory(&dips, sizeof(dips));
  271. dips.diph.dwSize = sizeof(dips);
  272. dips.diph.dwHeaderSize = sizeof(DIPROPHEADER);
  273. dips.diph.dwObj = 0;
  274. dips.diph.dwHow = DIPH_DEVICE;
  275. hr = lpDID->GetProperty(DIPROP_MAPFILE, &dips.diph);
  276. if (FAILED(hr))
  277. FAILURE(IDS_GETPROPMAPFILEFAILED);
  278. #ifdef UNICODE
  279. lstrcpy(szIniPath, dips.wsz);
  280. #else
  281. r = WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK|WC_DEFAULTCHAR, dips.wsz, -1, szIniPath, MAX_PATH, _T("0"), &bUsedDefault);
  282. dwError = GetLastError();
  283. if (0 == r)
  284. FAILURE(IDS_WCTOMBFAILED);
  285. #endif
  286. if (lstrlen(szIniPath) < 1)
  287. FAILURE(IDS_NOMAPFILEPATH);
  288. {
  289. int i;
  290. //////// Got map file name. Now write information to the file in 2 steps: ////////
  291. //////// write deleted views, write remaining views. ////////
  292. // Prepare deleted views array
  293. if (GetNumDeleteNotes())
  294. {
  295. pDelImgInfo = new DIDEVICEIMAGEINFOW[GetNumDeleteNotes()];
  296. if (!pDelImgInfo) FAILURE(IDS_ERROR_OUTOFMEMORY);
  297. for (int iDelIndex = 0; iDelIndex < GetNumDeleteNotes(); ++iDelIndex)
  298. {
  299. UIDELETENOTE Del;
  300. GetDeleteNote(Del, iDelIndex);
  301. pDelImgInfo[iDelIndex].dwFlags = DIDIFT_DELETE | (Del.eType == UIDNT_VIEW ? DIDIFT_CONFIGURATION : DIDIFT_OVERLAY);
  302. pDelImgInfo[iDelIndex].dwViewID = Del.nViewIndex;
  303. pDelImgInfo[iDelIndex].dwObjID = Del.dwObjID;
  304. }
  305. }
  306. // Initialize DIMAP class
  307. hInst = LoadLibrary(_T("DIMAP.DLL"));
  308. if (hInst)
  309. fpClassFactory = (LPFNGETCLASSOBJECT)GetProcAddress(hInst,"DllGetClassObject");
  310. if (!fpClassFactory)
  311. FAILURE(IDS_ERROR_CANTLOADDIMAP);
  312. hr = fpClassFactory(IID_IDirectInputMapClsFact, IID_IClassFactory, (void**)&pDiMapCF);
  313. if (FAILED(hr)) FAILURE(IDS_ERROR_CANTLOADDIMAP);
  314. hr = pDiMapCF->CreateInstance(NULL, IID_IDirectInputMapVendorIW, (void**)&lpDiMap); // Create mapper object
  315. if (FAILED(hr)) FAILURE(IDS_ERROR_CANTLOADDIMAP);
  316. hr = lpDiMap->Initialize(&guid, dips.wsz, 0); // Initialize with the INI file name
  317. if (FAILED(hr)) FAILURE(IDS_ERROR_CANTLOADDIMAP);
  318. // Prepare DIACTIONFORMAT for writing.
  319. DIDEVICEIMAGEINFOHEADERW ImgInfoHdr;
  320. LPDIACTIONFORMATW lpNewActFormat = NULL;
  321. // We can get the DIACTIONFORMAT for this device from the main CConfigWnd object.
  322. hr = m_UIFrame.GetActionFormatFromInstanceGuid(&lpNewActFormat, guid);
  323. if (FAILED(hr) || !lpNewActFormat)
  324. FAILURE(0);
  325. for (DWORD dwAct = 0; dwAct < lpNewActFormat->dwNumActions; ++dwAct)
  326. lpNewActFormat->rgoAction[dwAct].dwHow |= DIAH_HWDEFAULT;
  327. // Prepare DIDEVICEIMAGEINFOHEADER for writing.
  328. // Compute the number of DIDEVICEIMAGEINFO that we will need to fill out.
  329. DWORD dwNumImgInfo = 0;
  330. for (int i = 0; i < GetNumViews(); ++i)
  331. dwNumImgInfo += GetView(i)->GetNumControls() + 1; // The view itself is one element.
  332. ImgInfoHdr.dwSize = sizeof(ImgInfoHdr);
  333. ImgInfoHdr.dwSizeImageInfo = sizeof(DIDEVICEIMAGEINFOW);
  334. ImgInfoHdr.dwcViews = GetNumViews();
  335. ImgInfoHdr.dwcAxes = 0; // Not needed for writing.
  336. ImgInfoHdr.dwcButtons = 0; // Not needed for writing.
  337. ImgInfoHdr.dwcPOVs = 0; // Not needed for writing.
  338. // Send delete array first, but only if there is something to delete
  339. if (GetNumDeleteNotes())
  340. {
  341. ImgInfoHdr.dwBufferSize =
  342. ImgInfoHdr.dwBufferUsed = GetNumDeleteNotes() * sizeof(DIDEVICEIMAGEINFOW);
  343. ImgInfoHdr.lprgImageInfoArray = pDelImgInfo;
  344. hr = lpDiMap->WriteVendorFile(lpNewActFormat, &ImgInfoHdr, 0); // Write it
  345. if (FAILED(hr))
  346. {
  347. if (hr == E_ACCESSDENIED)
  348. {
  349. FAILURE(IDS_WRITEVENDORFILE_ACCESSDENIED);
  350. }
  351. else
  352. {
  353. FAILURE(IDS_ERROR_WRITEVENDORFILE_FAILED);
  354. }
  355. }
  356. }
  357. // Update a few fields for writing remaining views.
  358. ImgInfoHdr.dwBufferSize =
  359. ImgInfoHdr.dwBufferUsed = dwNumImgInfo * sizeof(DIDEVICEIMAGEINFOW);
  360. ImgInfoHdr.lprgImageInfoArray = new DIDEVICEIMAGEINFOW[dwNumImgInfo];
  361. if (!ImgInfoHdr.lprgImageInfoArray)
  362. FAILURE(IDS_ERROR_OUTOFMEMORY);
  363. // Get a default image filename so that if a view doesn't have one, we'll use the default.
  364. // For now, default image is the image used by the first view for which an image exists.
  365. TCHAR tszDefImgPath[MAX_PATH] = _T("");
  366. for (int iCurrView = 0; iCurrView < GetNumViews(); ++iCurrView)
  367. {
  368. CDeviceView *pView = GetView(iCurrView);
  369. if (pView->GetImagePath())
  370. {
  371. lstrcpy(tszDefImgPath, pView->GetImagePath());
  372. break;
  373. }
  374. }
  375. DWORD dwNextWriteOffset = 0; // This is the index that the next write operation will write to.
  376. int dwViewImgOffset = 0; // This is the index to be used for the next configuration image.
  377. // Now we fill in the DIDEVICEIMAGEINFO array by going through each view
  378. for (int iCurrView = 0; iCurrView < GetNumViews(); ++iCurrView)
  379. {
  380. CDeviceView *pView = GetView(iCurrView);
  381. // Convert image path from T to unicode
  382. #ifndef UNICODE
  383. WCHAR wszImagePath[MAX_PATH];
  384. if (pView->GetImagePath())
  385. MultiByteToWideChar(CP_ACP, 0, pView->GetImagePath(), -1, wszImagePath, MAX_PATH);
  386. else
  387. MultiByteToWideChar(CP_ACP, 0, tszDefImgPath, -1, wszImagePath, MAX_PATH);
  388. wcscpy(ImgInfoHdr.lprgImageInfoArray[dwNextWriteOffset].tszImagePath, wszImagePath);
  389. #else
  390. if (pView->GetImagePath())
  391. wcscpy(ImgInfoHdr.lprgImageInfoArray[dwNextWriteOffset].tszImagePath, pView->GetImagePath());
  392. else
  393. wcscpy(ImgInfoHdr.lprgImageInfoArray[dwNextWriteOffset].tszImagePath, tszDefImgPath); // String with a space
  394. #endif
  395. ImgInfoHdr.lprgImageInfoArray[dwNextWriteOffset].dwViewID = dwViewImgOffset; // Points to the view offset
  396. ImgInfoHdr.lprgImageInfoArray[dwNextWriteOffset].dwFlags = DIDIFT_CONFIGURATION;
  397. ++dwNextWriteOffset; // Increment the write index
  398. // Now iterate through the controls within this view
  399. for (int iCurrCtrl = 0; iCurrCtrl < pView->GetNumControls(); ++iCurrCtrl)
  400. {
  401. CDeviceControl *pCtrl = pView->GetControl(iCurrCtrl);
  402. pCtrl->FillImageInfo(&ImgInfoHdr.lprgImageInfoArray[dwNextWriteOffset]); // Fill in control info
  403. ImgInfoHdr.lprgImageInfoArray[dwNextWriteOffset].dwViewID = dwViewImgOffset; // Points to the view offset
  404. ++dwNextWriteOffset; // Increment the write index
  405. }
  406. ++dwViewImgOffset; // Increment dwViewImgOffset once per view
  407. }
  408. // Write to vendor file
  409. hr = lpDiMap->WriteVendorFile(lpNewActFormat, &ImgInfoHdr, 0);
  410. delete[] ImgInfoHdr.lprgImageInfoArray;
  411. if (FAILED(hr))
  412. {
  413. if (hr == E_ACCESSDENIED)
  414. {
  415. FAILURE(IDS_WRITEVENDORFILE_ACCESSDENIED);
  416. }
  417. else
  418. {
  419. FAILURE(IDS_ERROR_WRITEVENDORFILE_FAILED);
  420. }
  421. }
  422. // Recreate the device instances to get the change
  423. DEVICEUINOTIFY uin;
  424. uin.msg = DEVUINM_RENEWDEVICE;
  425. Notify(uin);
  426. }
  427. cleanup:
  428. delete[] pDelImgInfo;
  429. if (lpDiMap)
  430. lpDiMap->Release();
  431. if (pDiMapCF)
  432. pDiMapCF->Release();
  433. if (lpDID != NULL)
  434. lpDID->Release();
  435. if (lpDI != NULL)
  436. lpDI->Release();
  437. if (hInst)
  438. FreeLibrary(hInst);
  439. lpDiMap = NULL;
  440. pDiMapCF = NULL;
  441. lpDID = NULL;
  442. lpDI = NULL;
  443. hInst = NULL;
  444. if (!bFailed)
  445. FormattedMsgBox(g_hModule, m_hWnd, MB_OK | MB_ICONINFORMATION, IDS_MSGBOXTITLE_WRITEINISUCCEEDED, IDS_WROTEINITO, m_didi.tszInstanceName, szIniPath);
  446. else
  447. {
  448. switch (failure__ids)
  449. {
  450. case 0:
  451. break; // Case for keyboards and mice where we don't want any msg box to pop up.
  452. case IDS_GETPROPVIDPIDFAILED:
  453. case IDS_GETPROPMAPFILEFAILED:
  454. case IDS_WRITEVENDORFILE_ACCESSDENIED:
  455. FormattedErrorBox(g_hModule, m_hWnd, IDS_MSGBOXTITLE_WRITEINIFAILED, IDS_WRITEVENDORFILE_ACCESSDENIED);
  456. break;
  457. case IDS_ERROR_WRITEVENDORFILE_FAILED:
  458. FormattedErrorBox(g_hModule, m_hWnd, IDS_MSGBOXTITLE_WRITEINIFAILED, failure__ids, hr);
  459. break;
  460. case IDS_ERROR_INIREAD:
  461. FormattedErrorBox(g_hModule, m_hWnd, IDS_MSGBOXTITLE_WRITEINIFAILED, IDS_ERROR_INIREAD);
  462. break;
  463. case IDS_DICREATEFAILED:
  464. FormattedErrorBox(g_hModule, m_hWnd, IDS_MSGBOXTITLE_WRITEINIFAILED, IDS_DICREATEFAILED, diver, hr);
  465. break;
  466. case IDS_CREATEDEVICEFAILED:
  467. FormattedErrorBox(g_hModule, m_hWnd, IDS_MSGBOXTITLE_WRITEINIFAILED, IDS_CREATEDEVICEFAILED, GUIDSTR(guid), hr);
  468. break;
  469. case IDS_WCTOMBFAILED:
  470. FormattedLastErrorBox(g_hModule, m_hWnd, IDS_MSGBOXTITLE_WRITEINIFAILED, IDS_WCTOMBFAILED, IDS_WCTOMBFAILED);
  471. break;
  472. case IDS_NOMAPFILEPATH:
  473. FormattedErrorBox(g_hModule, m_hWnd, IDS_MSGBOXTITLE_WRITEINIFAILED, IDS_NOMAPFILEPATH);
  474. break;
  475. case IDS_ERROR_OUTOFMEMORY:
  476. FormattedErrorBox(g_hModule, m_hWnd, IDS_MSGBOXTITLE_WRITEINIFAILED, IDS_ERROR_OUTOFMEMORY);
  477. break;
  478. default:
  479. FormattedErrorBox(g_hModule, m_hWnd, IDS_MSGBOXTITLE_WRITEINIFAILED, IDS_ERRORUNKNOWN);
  480. break;
  481. }
  482. }
  483. return FALSE;
  484. #undef FAILURE
  485. }
  486. #endif
  487. //@@END_MSINTERNAL
  488. void CDeviceUI::SetDevice(LPDIRECTINPUTDEVICE8W lpDID)
  489. {
  490. m_priv_lpDID = lpDID;
  491. }
  492. BOOL CDeviceUI::IsControlMapped(CDeviceControl *pControl)
  493. {
  494. if (pControl == NULL || m_pNotify == NULL)
  495. return FALSE;
  496. return m_pNotify->IsControlMapped(pControl);
  497. }
  498. void CDeviceUI::Remove(CDeviceView *pView)
  499. {
  500. if (pView == NULL)
  501. return;
  502. int i = GetViewIndex(pView);
  503. if (i < 0 || i >= GetNumViews())
  504. {
  505. assert(0);
  506. return;
  507. }
  508. if (pView == m_pCurView)
  509. m_pCurView = NULL;
  510. if (m_arpView[i] != NULL)
  511. {
  512. m_arpView[i]->RemoveAll();
  513. delete m_arpView[i];
  514. }
  515. m_arpView[i] = NULL;
  516. m_arpView.RemoveAt(i);
  517. if (m_arpView.GetSize() < 1)
  518. RequireAtLeastOneView();
  519. else if (m_pCurView == NULL)
  520. {
  521. SetView(0);
  522. NumViewsChanged();
  523. }
  524. }
  525. void CDeviceUI::RemoveAll()
  526. {
  527. m_pCurView = NULL;
  528. for (int i = 0; i < GetNumViews(); i++)
  529. {
  530. if (m_arpView[i] != NULL)
  531. delete m_arpView[i];
  532. m_arpView[i] = NULL;
  533. }
  534. m_arpView.RemoveAll();
  535. RequireAtLeastOneView();
  536. }
  537. CDeviceView *CDeviceUI::NewView()
  538. {
  539. // allocate new view, continuing on if it fails
  540. CDeviceView *pView = new CDeviceView(*this);
  541. if (pView == NULL)
  542. return NULL;
  543. // add view to array
  544. m_arpView.SetAtGrow(m_arpView.GetSize(), pView);
  545. // create view
  546. pView->Create(m_hWnd, m_ViewRect, FALSE);
  547. // let the page update to indicate viewness
  548. NumViewsChanged();
  549. return pView;
  550. }
  551. CDeviceView *CDeviceUI::UserNewView()
  552. {
  553. CDeviceView *pView = NewView();
  554. if (!pView)
  555. return NULL;
  556. pView->AddWrappedLineOfText(
  557. (HFONT)m_uig.GetFont(UIE_PICCUSTOMTEXT),
  558. m_uig.GetTextColor(UIE_PICCUSTOMTEXT),
  559. m_uig.GetBkColor(UIE_PICCUSTOMTEXT),
  560. _T("Customize This View"));
  561. pView->MakeMissingImages();
  562. Invalidate();
  563. return pView;
  564. }
  565. void CDeviceUI::RequireAtLeastOneView()
  566. {
  567. if (GetNumViews() > 0)
  568. return;
  569. CDeviceView *pView = NewView();
  570. if (!pView)
  571. return;
  572. pView->AddWrappedLineOfText(
  573. (HFONT)m_uig.GetFont(UIE_PICCUSTOMTEXT),
  574. m_uig.GetTextColor(UIE_PICCUSTOMTEXT),
  575. m_uig.GetBkColor(UIE_PICCUSTOMTEXT),
  576. _T("Customize This View"));
  577. pView->AddWrappedLineOfText(
  578. (HFONT)m_uig.GetFont(UIE_PICCUSTOM2TEXT),
  579. m_uig.GetTextColor(UIE_PICCUSTOM2TEXT),
  580. m_uig.GetBkColor(UIE_PICCUSTOM2TEXT),
  581. _T("The UI requires at least one view per device"));
  582. pView->MakeMissingImages();
  583. SetView(pView);
  584. }
  585. void CDeviceUI::NumViewsChanged()
  586. {
  587. DEVICEUINOTIFY uin;
  588. uin.msg = DEVUINM_NUMVIEWSCHANGED;
  589. Notify(uin);
  590. }
  591. //@@BEGIN_MSINTERNAL
  592. #ifdef DDKBUILD
  593. void CDeviceUI::NoteDeleteView(CDeviceView *pView)
  594. {
  595. assert(pView != NULL);
  596. if (pView)
  597. NoteDeleteView(pView->GetViewIndex());
  598. }
  599. void CDeviceUI::NoteDeleteControl(CDeviceControl *pControl)
  600. {
  601. assert(pControl != NULL);
  602. if (pControl)
  603. NoteDeleteControl(pControl->GetViewIndex(),
  604. pControl->GetControlIndex(),
  605. pControl->GetOffset());
  606. }
  607. void CDeviceUI::NoteDeleteView(int nView)
  608. {
  609. NoteDeleteAllControlsForView(GetView(nView));
  610. int last = m_DeleteNotes.GetSize();
  611. m_DeleteNotes.SetSize(last + 1);
  612. UIDELETENOTE &uidn = m_DeleteNotes[last];
  613. uidn.eType = UIDNT_VIEW;
  614. uidn.nViewIndex = nView;
  615. }
  616. void CDeviceUI::NoteDeleteControl(int nView, int nControl, DWORD dwObjID)
  617. {
  618. int last = m_DeleteNotes.GetSize();
  619. m_DeleteNotes.SetSize(last + 1);
  620. UIDELETENOTE &uidn = m_DeleteNotes[last];
  621. uidn.eType = UIDNT_CONTROL;
  622. uidn.nViewIndex = nView;
  623. uidn.nControlIndex = nControl;
  624. uidn.dwObjID = dwObjID;
  625. }
  626. int CDeviceUI::GetNumDeleteNotes()
  627. {
  628. return m_DeleteNotes.GetSize();
  629. }
  630. BOOL CDeviceUI::GetDeleteNote(UIDELETENOTE &uidn, int i)
  631. {
  632. if (i >= 0 && i < GetNumDeleteNotes())
  633. {
  634. uidn = m_DeleteNotes[i];
  635. return TRUE;
  636. }
  637. return FALSE;
  638. }
  639. void CDeviceUI::ClearDeleteNotes()
  640. {
  641. m_DeleteNotes.RemoveAll();
  642. }
  643. void CDeviceUI::DumpDeleteNotes()
  644. {
  645. utilstr s, suffix;
  646. suffix.Format(_T("for device %s"), QSAFESTR(m_didi.tszInstanceName));
  647. int n = GetNumDeleteNotes();
  648. if (!n)
  649. {
  650. s.Format(_T("No DeleteNotes %s\n\n"), suffix.Get());
  651. trace(s.Get());
  652. return;
  653. }
  654. s.Format(_T("%d DeleteNotes %s...\n"), n, suffix.Get());
  655. tracescope(__ts, s.Get());
  656. for (int i = 0; i < n; i++)
  657. {
  658. UIDELETENOTE uidn;
  659. GetDeleteNote(uidn, i);
  660. switch (uidn.eType)
  661. {
  662. case UIDNT_VIEW:
  663. s.Format(_T("%02d: View %d\n"), i, uidn.nViewIndex);
  664. break;
  665. case UIDNT_CONTROL:
  666. s.Format(_T("%02d: Control %d on View %d, dwObjID = 0x%08x (%d)\n"),
  667. i, uidn.nControlIndex, uidn.nViewIndex, uidn.dwObjID, uidn.dwObjID);
  668. break;
  669. }
  670. trace(s.Get());
  671. }
  672. trace(_T("\n"));
  673. }
  674. void CDeviceUI::NoteDeleteAllControlsForView(CDeviceView *pView)
  675. {
  676. if (!pView)
  677. return;
  678. for (int i = 0; i < pView->GetNumControls(); i++)
  679. NoteDeleteControl(pView->GetControl(i));
  680. }
  681. void CDeviceUI::NoteDeleteAllViews()
  682. {
  683. for (int i = 0; i < GetNumViews(); i++)
  684. NoteDeleteView(GetView(i));
  685. }
  686. #endif
  687. //@@END_MSINTERNAL