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.

2176 lines
49 KiB

  1. //-----------------------------------------------------------------------------
  2. // File: configwnd.cpp
  3. //
  4. // Desc: CConfigWnd is derived from CFlexWnd. It implements the top-level
  5. // UI window which all other windows are descendents of.
  6. //
  7. // Functionalities handled by CConfigWnd are device tabs, Reset, Ok,
  8. // and Cancel buttons.
  9. //
  10. // Copyright (C) 1999-2000 Microsoft Corporation. All Rights Reserved.
  11. //-----------------------------------------------------------------------------
  12. #include "common.hpp"
  13. LPCTSTR g_tszAppWindowName = _T("DINPUT Default Mapper UI");
  14. const int WINDOW_WIDTH = 640;
  15. const int WINDOW_HEIGHT = 480;
  16. const int TABTEXTMARGINLEFT = 7;
  17. const int TABTEXTMARGINTOP = 3;
  18. const int TABTEXTMARGINRIGHT = 7;
  19. const int TABTEXTMARGINBOTTOM = 4;
  20. const int BUTTONTEXTMARGINLEFT = 7;
  21. const int BUTTONTEXTMARGINTOP = 3;
  22. const int BUTTONTEXTMARGINRIGHT = 7;
  23. const int BUTTONTEXTMARGINBOTTOM = 4;
  24. const int BARBUTTONMARGINLEFT = 9;
  25. const int BARBUTTONMARGINTOP = 4;
  26. const int BARBUTTONMARGINRIGHT = 9;
  27. const int BARBUTTONMARGINBOTTOM = 5;
  28. const int BARBUTTONSPACING = 4;
  29. //#define WM_QUERYACTIONASSIGNEDANYWHERE (WM_USER + 4)
  30. CConfigWnd::CConfigWnd(CUIGlobals &uig) :
  31. m_uig(uig),
  32. m_bCreated(FALSE),
  33. m_pPageFactory(NULL),
  34. m_hPageFactoryInst(NULL),
  35. m_pSurface(NULL),
  36. m_pSurface3D(NULL),
  37. //@@BEGIN_MSINTERNAL
  38. #ifdef DDKBUILD
  39. m_bEditLayout(uig.QueryAllowEditLayout()),
  40. #endif
  41. //@@END_MSINTERNAL
  42. m_CurSel(-1),
  43. m_nCurGenre(0),
  44. m_pbmTopGradient(NULL),
  45. m_pbmBottomGradient(NULL),
  46. m_pbmPointerEraser(NULL),
  47. m_pbm3D(NULL),
  48. m_p3DBits(NULL),
  49. m_SurfFormat(D3DFMT_UNKNOWN),
  50. m_uiPixelSize(4),
  51. m_bBitmapsMapped(FALSE),
  52. m_lpDI(NULL),
  53. m_bScrollTabs(FALSE),
  54. m_bScrollTabsLeft(FALSE),
  55. m_bScrollTabsRight(FALSE),
  56. m_nLeftTab(0),
  57. m_dwInitFlags(0),
  58. m_bHourGlass(FALSE),
  59. m_bNeedRedraw(FALSE)
  60. {
  61. tracescope(__ts, _T("CConfigWnd::CConfigWnd()\n"));
  62. m_lpDI = m_uig.GetDI();
  63. m_pSurface = m_uig.GetSurface();
  64. m_pSurface3D = m_uig.GetSurface3D();
  65. if (m_pSurface != NULL || m_pSurface3D != NULL)
  66. {
  67. if (m_pSurface != NULL && m_pSurface3D != NULL)
  68. {
  69. etrace(_T("Both Surface and Surface3D are non-NULL, will use only Surface3D\n"));
  70. m_pSurface->Release();
  71. m_pSurface = NULL;
  72. assert(m_pSurface3D != NULL);
  73. assert(m_pSurface == NULL);
  74. }
  75. assert(m_pSurface != NULL || m_pSurface3D != NULL);
  76. assert(!(m_pSurface != NULL && m_pSurface3D != NULL));
  77. m_bRender3D = (m_pSurface3D != NULL);
  78. SetRenderMode();
  79. trace(_T("RenderMode set\n"));
  80. traceBOOL(m_bRender3D);
  81. if (m_bRender3D)
  82. Create3DBitmap();
  83. HDC hDC = GetRenderDC();
  84. if (hDC != NULL)
  85. {
  86. m_pbmPointerEraser = CBitmap::Create(
  87. GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON),
  88. hDC);
  89. ReleaseRenderDC(hDC);
  90. }
  91. else
  92. etrace(_T("Failed to get Render DC"));
  93. }
  94. }
  95. CConfigWnd::~CConfigWnd()
  96. {
  97. tracescope(__ts, _T("CConfigWnd::~CConfigWnd()\n"));
  98. ClearList();
  99. if (m_lpDI != NULL)
  100. m_lpDI->Release();
  101. m_lpDI = NULL;
  102. if (m_pSurface != NULL)
  103. m_pSurface->Release();
  104. m_pSurface = NULL;
  105. if (m_pSurface3D != NULL)
  106. m_pSurface3D->Release();
  107. m_pSurface3D = NULL;
  108. if (m_pPageFactory != NULL)
  109. m_pPageFactory->Release();
  110. m_pPageFactory = NULL;
  111. if (m_hPageFactoryInst != NULL)
  112. FreeLibrary(m_hPageFactoryInst);
  113. m_hPageFactoryInst = NULL;
  114. if (m_pbmPointerEraser != NULL)
  115. delete m_pbmPointerEraser;
  116. m_pbmPointerEraser = NULL;
  117. if (m_pbm3D != NULL)
  118. delete m_pbm3D;
  119. m_pbm3D = NULL;
  120. if (m_pbmTopGradient != NULL)
  121. delete m_pbmTopGradient;
  122. m_pbmTopGradient = NULL;
  123. if (m_pbmBottomGradient != NULL)
  124. delete m_pbmBottomGradient;
  125. m_pbmBottomGradient = NULL;
  126. }
  127. HWND CMouseTrap::Create(HWND hParent, BOOL bInRenderMode)
  128. {
  129. if (m_hWnd)
  130. return m_hWnd;
  131. m_hParent = hParent;
  132. int sx = GetSystemMetrics(SM_CXSCREEN);
  133. int sy = GetSystemMetrics(SM_CYSCREEN);
  134. RECT rect = {0, 0, sx, sy};
  135. // If we are not in render mode, the trap window is exactly the same as the parent window
  136. if (!bInRenderMode)
  137. GetWindowRect(hParent, &rect);
  138. return CFlexWnd::Create(
  139. hParent,
  140. NULL,
  141. WS_EX_TOPMOST,
  142. WS_POPUP | WS_VISIBLE,
  143. rect);
  144. }
  145. BOOL CConfigWnd::Create(HWND hParent)
  146. {
  147. tracescope(__ts, _T("CConfigWnd::Create()\n"));
  148. traceHEX(hParent);
  149. HRESULT hresult = PrivGetClassObject(CLSID_CDIDeviceActionConfigPage, CLSCTX_INPROC_SERVER, NULL, IID_IClassFactory, (LPVOID*) &m_pPageFactory, &m_hPageFactoryInst);
  150. if (FAILED(hresult))
  151. {
  152. // TODO: indicate failure to create page factory
  153. m_pPageFactory = NULL;
  154. m_hPageFactoryInst = NULL;
  155. etrace1(_T("Failed to create page classfactory, PrivGetClassObject() returned 0x%08x\n"), hresult);
  156. return FALSE;
  157. }
  158. int sx = GetSystemMetrics(SM_CXSCREEN);
  159. int sy = GetSystemMetrics(SM_CYSCREEN);
  160. int w = WINDOW_WIDTH;
  161. int h = WINDOW_HEIGHT;
  162. int rx = sx - w;
  163. int ry = sy - h;
  164. RECT rect = {rx / 2, ry / 2, 0, 0};
  165. rect.right = rect.left + w;
  166. rect.bottom = rect.top + h;
  167. HWND hConfigParent = hParent;
  168. if (InRenderMode())
  169. {
  170. hConfigParent = m_MouseTrap.Create(hParent, InRenderMode());
  171. if (hConfigParent == NULL)
  172. hConfigParent = hParent;
  173. }
  174. HWND hRet = CFlexWnd::Create(
  175. hConfigParent,
  176. g_tszAppWindowName,
  177. 0,
  178. WS_POPUP | WS_VISIBLE | WS_CLIPCHILDREN,
  179. rect);
  180. if (hRet == NULL)
  181. etrace(_T("CFlexWnd::Create() failed!\n"));
  182. // Set the cursor extent to this window if we are in render mode (full-screen)
  183. if (InRenderMode())
  184. {
  185. RECT rc;
  186. GetWindowRect(m_hWnd, &rc);
  187. ClipCursor(&rc);
  188. }
  189. return NULL != hRet;
  190. }
  191. void CConfigWnd::SetForegroundWindow()
  192. {
  193. // find the window
  194. HWND hWnd = FindWindow(GetDefaultClassName(), g_tszAppWindowName);
  195. // activate it if found
  196. if (NULL != hWnd)
  197. ::SetForegroundWindow(hWnd);
  198. }
  199. void CConfigWnd::OnPaint(HDC hDC)
  200. {
  201. if (hDC == NULL)
  202. return;
  203. SIZE topsize = GetRectSize(m_rectTopGradient);
  204. SIZE bottomsize = GetRectSize(m_rectBottomGradient);
  205. SIZE bsize = {max(topsize.cx, bottomsize.cx),
  206. max(topsize.cy, bottomsize.cy)};
  207. CBitmap *pbm = CBitmap::Create(bsize, hDC);
  208. if (pbm == NULL)
  209. return;
  210. HDC hBDC = NULL, hODC = hDC;
  211. if (m_bHourGlass)
  212. {
  213. if (!InRenderMode())
  214. {
  215. // If not in fullscreen mode, change cursor to hourglass
  216. HCURSOR hCursor;
  217. hCursor = LoadCursor(NULL, IDC_WAIT);
  218. SetCursor(hCursor);
  219. } else
  220. {
  221. // If in fullscreen mode, hide the cursor during reset process.
  222. SetCursor(NULL);
  223. }
  224. }
  225. hBDC = pbm->BeginPaintInto(hDC);
  226. if (hBDC == NULL)
  227. {
  228. delete pbm;
  229. return;
  230. }
  231. hDC = hBDC;
  232. if (m_pbmTopGradient != NULL)
  233. m_pbmTopGradient->Draw(hDC);
  234. {
  235. CPaintHelper ph(m_uig, hDC);
  236. ph.SetElement(UIE_BORDER);
  237. ph.MoveTo(0, m_rectTopGradient.bottom - 1);
  238. ph.LineTo(WINDOW_WIDTH, m_rectTopGradient.bottom - 1);
  239. int i;
  240. for (i = 0; i < GetNumElements(); i++)
  241. {
  242. const ELEMENT &e = GetElement(i);
  243. BOOL bSel = i == m_CurSel;
  244. ph.SetElement(bSel ? UIE_SELTAB : UIE_TAB);
  245. ph.Rectangle(e.rect);
  246. RECT trect = e.textrect;
  247. DrawText(hDC, e.tszCaption, -1, &trect, DT_NOCLIP | DT_NOPREFIX);
  248. if (bSel)
  249. {
  250. ph.SetPen(UIP_BLACK);
  251. ph.MoveTo(e.rect.left + 1, e.rect.bottom - 1);
  252. ph.LineTo(e.rect.right - 1, e.rect.bottom - 1);
  253. }
  254. }
  255. if (m_bScrollTabs && GetNumElements() > 0)
  256. {
  257. ph.SetElement(UIE_TABARROW);
  258. const ELEMENT &e = GetElement(0);
  259. int h = e.rect.bottom - e.rect.top;
  260. for (i = 0; i < 2; i++)
  261. {
  262. RECT &rect = i == 0 ? m_rectSTRight : m_rectSTLeft;
  263. BOOL bDraw = i ? m_bScrollTabsLeft : m_bScrollTabsRight;
  264. ph.Rectangle(rect);
  265. if (!bDraw)
  266. continue;
  267. int d,l,r,m,t,b, f = !i, w;
  268. w = rect.right - rect.left;
  269. l = f ? w / 4 : 3 * w / 8;
  270. r = f ? 5 * w / 8 : 3 * w / 4;
  271. d = r - l;
  272. m = w / 2;
  273. t = m - d;
  274. b = m + d;
  275. l += rect.left;
  276. r += rect.left;
  277. POINT p[4];
  278. p[3].x = p[0].x = f ? l : r;
  279. p[2].x = p[1].x = f ? r : l;
  280. p[3].y = p[0].y = m;
  281. p[1].y = t;
  282. p[2].y = b;
  283. Polyline(hDC, p, 4);
  284. }
  285. }
  286. }
  287. pbm->Draw(hODC, topsize);
  288. m_pbmBottomGradient->Draw(hDC);
  289. {
  290. CPaintHelper ph(m_uig, hDC);
  291. ph.SetElement(UIE_BORDER);
  292. Rectangle(hDC, 0, -1, WINDOW_WIDTH,
  293. GetRectSize(m_rectBottomGradient).cy);
  294. for (int i = 0; i < NUMBUTTONS; i++)
  295. {
  296. BOOL bOkOnly = !m_uig.InEditMode();
  297. const BUTTON &b = m_Button[i];
  298. //@@BEGIN_MSINTERNAL
  299. #ifdef DDKBUILD
  300. BOOL bLayoutButton = i == BUTTON_LAYOUT;
  301. if (!m_uig.QueryAllowEditLayout() && bLayoutButton)
  302. continue;
  303. #endif
  304. //@@END_MSINTERNAL
  305. if ( bOkOnly && i != BUTTON_CANCEL
  306. //@@BEGIN_MSINTERNAL
  307. #ifdef DDKBUILD
  308. && !bLayoutButton
  309. #endif
  310. //@@END_MSINTERNAL
  311. )
  312. continue;
  313. if (i == BUTTON_OK || bOkOnly)
  314. ph.SetElement(UIE_DEFBUTTON);
  315. else
  316. ph.SetElement(UIE_BUTTON);
  317. int ay = m_rectBottomGradient.top;
  318. ph.Rectangle(b.rect.left, b.rect.top - ay, b.rect.right, b.rect.bottom - ay);
  319. RECT trect = b.textrect;
  320. OffsetRect(&trect, 0, -ay);
  321. DrawText(hDC, b.tszCaption, -1, &trect, DT_NOCLIP | DT_NOPREFIX);
  322. }
  323. }
  324. pbm->Draw(hODC, m_rectBottomGradient.left, m_rectBottomGradient.top, bottomsize);
  325. pbm->EndPaintInto(hBDC);
  326. delete pbm;
  327. hDC = hODC;
  328. {
  329. CPaintHelper ph(m_uig, hDC);
  330. ph.SetElement(UIE_BORDER);
  331. ph.MoveTo(0, m_rectTopGradient.bottom);
  332. ph.LineTo(0, m_rectBottomGradient.top);
  333. ph.MoveTo(WINDOW_WIDTH - 1, m_rectTopGradient.bottom);
  334. ph.LineTo(WINDOW_WIDTH - 1, m_rectBottomGradient.top);
  335. }
  336. }
  337. void CConfigWnd::OnClick(POINT point, WPARAM fwKeys, BOOL bLeft)
  338. {
  339. int i;
  340. // Un-highlight the current callout
  341. SendMessage(CFlexWnd::s_CurrPageHwnd, WM_UNHIGHLIGHT, 0, 0);
  342. // check scroll tab buttons
  343. if (m_bScrollTabs)
  344. for (i = 0; i < 2; i++)
  345. {
  346. RECT &r = !i ? m_rectSTRight : m_rectSTLeft;
  347. BOOL b = !i ? m_bScrollTabsRight : m_bScrollTabsLeft;
  348. if (PtInRect(&r, point))
  349. {
  350. if (b)
  351. ScrollTabs(!i ? -1 : 1);
  352. return;
  353. }
  354. }
  355. // check tabs
  356. for (i = 0; i < GetNumElements(); i++)
  357. if (PtInRect(&(GetElement(i).rect), point))
  358. {
  359. // Check if the tab is partially obscured. If so we scroll the tab so it becomes completely visible.
  360. POINT pt = {m_rectSTLeft.left, m_rectSTLeft.top};
  361. if (m_bScrollTabsRight || m_bScrollTabsLeft)
  362. {
  363. while (PtInRect(&(GetElement(i).rect), pt))
  364. ScrollTabs(1);
  365. }
  366. SelTab(i);
  367. return;
  368. }
  369. // check buttons
  370. for (i = 0; i < NUMBUTTONS; i++)
  371. if (PtInRect(&(m_Button[i].rect), point))
  372. {
  373. FireButton(i);
  374. return;
  375. }
  376. }
  377. void CConfigWnd::ScrollTabs(int by)
  378. {
  379. m_nLeftTab += by;
  380. if (m_nLeftTab < 0)
  381. m_nLeftTab = 0;
  382. if (m_nLeftTab >= GetNumElements())
  383. m_nLeftTab = GetNumElements() - 1;
  384. CalcTabs();
  385. Invalidate();
  386. }
  387. void CConfigWnd::OnDestroy()
  388. {
  389. tracescope(__ts, _T("CConfigWnd::OnDestroy()\n"));
  390. ClipCursor(NULL); // Set cursor extent to entire desktop.
  391. if (m_bCreated)
  392. PostQuitMessage(EXIT_SUCCESS);
  393. }
  394. LRESULT CConfigWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)
  395. {
  396. tracescope(__ts, _T("CConfigWnd::OnCreate()\n"));
  397. if (!Init())
  398. {
  399. etrace(_T("CConfigWnd::Init() failed\n"));
  400. return -1;
  401. }
  402. else
  403. m_bCreated = TRUE;
  404. return 0;
  405. }
  406. BOOL CALLBACK EnumDeviceCallback(const DIDEVICEINSTANCEW *lpdidi, LPDIRECTINPUTDEVICE8W pdiDev8W, DWORD dwFlags, DWORD dwDeviceRemaining, LPVOID pvRef)
  407. {
  408. if (pvRef != NULL)
  409. return ((CConfigWnd *)pvRef)->EnumDeviceCallback(lpdidi);
  410. else
  411. return DIENUM_STOP;
  412. }
  413. BOOL CConfigWnd::EnumDeviceCallback(const DIDEVICEINSTANCEW *lpdidi)
  414. {
  415. DIDEVICEINSTANCEW didi;
  416. didi.dwSize = sizeof(DIDEVICEINSTANCEW);
  417. didi.guidInstance = lpdidi->guidInstance;
  418. didi.guidProduct = lpdidi->guidProduct;
  419. didi.dwDevType = lpdidi->dwDevType;
  420. CopyStr(didi.tszInstanceName, lpdidi->tszInstanceName, MAX_PATH);
  421. CopyStr(didi.tszProductName, lpdidi->tszProductName, MAX_PATH);
  422. didi.guidFFDriver = lpdidi->guidFFDriver;
  423. didi.wUsagePage = lpdidi->wUsagePage;
  424. didi.wUsage = lpdidi->wUsage;
  425. AddToList(&didi);
  426. return DIENUM_CONTINUE;
  427. }
  428. // show any error message here if returning false
  429. BOOL CConfigWnd::Init(DWORD dwInitFlags)
  430. {
  431. tracescope(__ts, _T("CConfigWnd::Init()\n"));
  432. HRESULT hr = S_OK;
  433. BOOL bReInit = !!(dwInitFlags & CFGWND_INIT_REINIT);
  434. m_dwInitFlags = dwInitFlags;
  435. SetOnFunctionExit<DWORD> _set_m_dwInitFlags(m_dwInitFlags, 0);
  436. // make sure we have DI
  437. assert(m_lpDI != NULL);
  438. if (m_lpDI == NULL)
  439. {
  440. etrace(_T("NULL m_lpDI\n"));
  441. return FALSE;
  442. }
  443. if (!(dwInitFlags & CFGWND_INIT_RESET))
  444. {
  445. // If we are not doing reset, clear device list then re-enumerate and rebuild.
  446. // clear list
  447. ClearList();
  448. // enum devices
  449. {
  450. tracescope(ts, _T("Enumerating Devices...\n\n"));
  451. DWORD dwFlags = DIEDBSFL_ATTACHEDONLY;
  452. hr = m_lpDI->EnumDevicesBySemantics(NULL, (LPDIACTIONFORMATW)&m_uig.RefMasterAcFor(m_nCurGenre), ::EnumDeviceCallback, (LPVOID)this, dwFlags);
  453. trace(_T("\n"));
  454. }
  455. } else
  456. {
  457. DIDEVICEINSTANCEW didiCopy;
  458. // Saves a copy of device instance as the current ELEMENT will be freed by AddToList().
  459. CopyMemory(&didiCopy, &GetElement(m_CurSel).didi, sizeof(didiCopy));
  460. // If resetting, call AddToList with bReset as TRUE to just get default mappings.
  461. AddToList(&didiCopy, TRUE);
  462. }
  463. // handle potential enum failure
  464. if (FAILED(hr))
  465. {
  466. etrace1(_T("EnumDevicesBySemantics() failed, returning 0x%08x\n"), hr);
  467. return FALSE;
  468. }
  469. // if there are no elements, fail
  470. if (GetNumElements() < 1)
  471. {
  472. etrace(_T("No devices\n"));
  473. return FALSE;
  474. }
  475. // calculate tabs, buttons, init gradients
  476. CalcTabs();
  477. if (!bReInit)
  478. {
  479. CalcButtons();
  480. InitGradients();
  481. // set the timer
  482. if (InRenderMode())
  483. {
  484. if (g_fptimeSetEvent)
  485. g_fptimeSetEvent(20, 20, CConfigWnd::TimerProc,
  486. (DWORD_PTR)m_hWnd, TIME_ONESHOT);
  487. Render();
  488. }
  489. }
  490. // make sure all the pages are in the right place
  491. PlacePages();
  492. // show the first page if we are not resetting. Show current page if we are.
  493. int CurSel = (dwInitFlags & CFGWND_INIT_RESET) ? m_CurSel : 0;
  494. m_CurSel = -1;
  495. SelTab(CurSel);
  496. // if we're already editting the layout, set it.
  497. // KLUDGE, set false and toggle to set
  498. if (m_bEditLayout)
  499. {
  500. m_bEditLayout = FALSE;
  501. ToggleLayoutEditting();
  502. }
  503. trace(_T("\n"));
  504. return TRUE;
  505. }
  506. // This is called once for each device that will get configured.
  507. int CConfigWnd::AddToList(const DIDEVICEINSTANCEW *lpdidi, BOOL bReset)
  508. {
  509. if (lpdidi == NULL)
  510. {
  511. etrace(_T("NULL lpdidi"));
  512. assert(0);
  513. return GetNumElements();
  514. }
  515. int i;
  516. tracescope(ts, _T("Adding Device "));
  517. trace(QSAFESTR(lpdidi->tszInstanceName));
  518. trace(_T("\n\n"));
  519. // add an element and get it if we are not doing reset (adding new device)
  520. if (!bReset)
  521. {
  522. i = GetNumElements();
  523. m_Element.SetSize(i + 1);
  524. }
  525. else
  526. {
  527. i = m_CurSel;
  528. ClearElement(m_CurSel, bReset); // If resetting, clear the current ELEMENT as we will populate it below.
  529. }
  530. // If we are doing reset, then we use the existing ELEMENT that this device is already using.
  531. ELEMENT &e = bReset ? GetElement(m_CurSel) : GetElement(i);
  532. // set various needed variables
  533. e.didi = *lpdidi;
  534. e.bCalc = FALSE;
  535. e.pUIGlobals = &m_uig;
  536. // create and set the device
  537. if (m_lpDI == NULL)
  538. {
  539. e.lpDID = NULL;
  540. etrace(_T("m_lpDI NULL! Can't create this device.\n"));
  541. }
  542. else
  543. {
  544. e.lpDID = CreateDevice(e.didi.guidInstance);
  545. if (!e.lpDID)
  546. etrace(_T("Failed to create device!\n"));
  547. }
  548. if (!bReset)
  549. {
  550. // Find owner of device only if we are not doing reset.
  551. // set starting current user index
  552. DIPROPSTRING dips;
  553. dips.diph.dwSize = sizeof(DIPROPSTRING);
  554. dips.diph.dwHeaderSize = sizeof(DIPROPHEADER);
  555. dips.diph.dwObj = DIPH_DEVICE;
  556. dips.diph.dwHow = 0;
  557. CopyStr(dips.wsz, "", MAX_PATH);
  558. if (!e.lpDID)
  559. {
  560. etrace(_T("no lpDID, assuming device unassigned\n"));
  561. e.nCurUser = -1;
  562. }
  563. //@@BEGIN_MSINTERNAL
  564. #ifdef DDKBUILD
  565. else if (m_uig.QueryAllowEditLayout())
  566. {
  567. trace(_T("In DDK mode. Set user to 0 automatically.\n"));
  568. e.nCurUser = 0;
  569. }
  570. #endif
  571. //@@END_MSINTERNAL
  572. else
  573. {
  574. HRESULT hr = e.lpDID->GetProperty(DIPROP_USERNAME, (LPDIPROPHEADER)&dips);
  575. e.nCurUser = -1; // unassigned unless getusernameindex below works
  576. if (FAILED(hr))
  577. etrace(_T("GetProperty(DIPROP_USERNAME,...) failed\n"));
  578. else if (hr == S_FALSE)
  579. trace(_T("GetProperty(DIPROP_USERNAME,...) returned S_FALSE\n"));
  580. else if (StrLen(dips.wsz) < 1)
  581. trace(_T("GetProperty(DIPROP_USERNAME,...) returned empty string\n"));
  582. else
  583. {
  584. trace(_T("Getting user name index for "));
  585. traceWSTR(dips.wsz);
  586. e.nCurUser = m_uig.GetUserNameIndex(dips.wsz);
  587. trace(_T("Result: "));
  588. traceLONG(e.nCurUser);
  589. if (e.nCurUser == -1)
  590. etrace(_T("Device assigned to user not passed to ConfigureDevices()\nConsidering unassigned now\n"));
  591. }
  592. }
  593. }
  594. // create and set the page object
  595. HWND hwndChild = NULL;
  596. e.pPage = CreatePageObject(i, e, hwndChild);
  597. if (e.pPage == NULL)
  598. etrace(_T("Failed to create page object!\n"));
  599. e.hWnd = hwndChild;
  600. if (e.hWnd == NULL)
  601. etrace(_T("CreatePageObject() returned NULL hwnd!\n"));
  602. // create/test the first acfor for this device with cur genre/user
  603. traceLONG(m_nCurGenre);
  604. traceLONG(e.nCurUser);
  605. LPDIACTIONFORMATW lpAcFor = NULL;
  606. if (e.nCurUser != -1)
  607. {
  608. lpAcFor = e.GetAcFor(m_nCurGenre, e.nCurUser, bReset);
  609. if (lpAcFor != NULL)
  610. TraceActionFormat(_T("Starting Device ActionFormat:"), *lpAcFor);
  611. else
  612. etrace(_T("Failed to create starting ActionFormat\n"));
  613. }
  614. else
  615. trace(_T("Device unassigned\n"));
  616. // check if anything was unsuccessful
  617. if ((lpAcFor == NULL && e.nCurUser != -1) || e.lpDID == NULL || e.pPage == NULL || e.hWnd == NULL)
  618. {
  619. // clear what was successful, set the size back (remove element),
  620. // and indicate error
  621. ClearElement(e);
  622. m_Element.SetSize(i);
  623. etrace(_T("Can't add this device - Element removed\n"));
  624. }
  625. trace(_T("\n"));
  626. return GetNumElements();
  627. }
  628. LPDIRECTINPUTDEVICE8W CConfigWnd::CreateDevice(GUID &guid)
  629. {
  630. LPDIRECTINPUTDEVICE8W lpDID;
  631. HRESULT hr = m_lpDI->CreateDevice(guid, &lpDID, NULL);
  632. if (FAILED(hr) || lpDID == NULL)
  633. {
  634. etrace2(_T("Could not create device (guid %s), CreateDevice() returned 0x%08x\n"), GUIDSTR(guid), hr);
  635. return NULL;
  636. }
  637. return lpDID;
  638. }
  639. void CConfigWnd::ClearElement(int i, BOOL bReset)
  640. {
  641. ELEMENT &e = GetElement(i);
  642. ClearElement(e, bReset);
  643. }
  644. void CConfigWnd::ClearElement(ELEMENT &e, BOOL bReset)
  645. {
  646. if (e.pPage != NULL)
  647. DestroyPageObject(e.pPage);
  648. if (e.lpDID != NULL)
  649. {
  650. e.lpDID->Release();
  651. e.lpDID = NULL;
  652. }
  653. e.pPage = NULL;
  654. e.lpDID = NULL;
  655. e.hWnd = NULL;
  656. e.pUIGlobals = NULL; // not freed
  657. if (!bReset) // Free map only if we are not resetting (delete permanently).
  658. e.FreeMap();
  659. }
  660. void CConfigWnd::ClearList()
  661. {
  662. int i;
  663. for (i = 0; i < GetNumElements(); i++)
  664. ClearElement(i);
  665. m_Element.RemoveAll();
  666. assert(!GetNumElements());
  667. }
  668. void CConfigWnd::PlacePages()
  669. {
  670. RECT rect;
  671. GetPageRect(rect);
  672. for (int i = 0; i < GetNumElements(); i++)
  673. {
  674. DWORD flags = SWP_NOZORDER | SWP_NOACTIVATE;
  675. SetWindowPos(GetElement(i).hWnd, NULL,
  676. rect.left, rect.top,
  677. rect.right - rect.left,
  678. rect.bottom - rect.top, flags);
  679. }
  680. }
  681. SIZE CConfigWnd::GetTextSize(LPCTSTR tszText)
  682. {
  683. RECT trect = {0, 0, 1, 1};
  684. HDC hDC = CreateCompatibleDC(NULL);
  685. if (hDC != NULL)
  686. {
  687. {
  688. CPaintHelper ph(m_uig, hDC);
  689. ph.SetFont(UIF_FRAME);
  690. DrawText(hDC, tszText, -1, &trect, DT_CALCRECT | DT_NOPREFIX);
  691. }
  692. DeleteDC(hDC);
  693. }
  694. SIZE size = {trect.right - trect.left, trect.bottom - trect.top};
  695. return size;
  696. }
  697. void CConfigWnd::InitGradients()
  698. {
  699. if (m_pbmTopGradient == NULL)
  700. m_pbmTopGradient = CBitmap::CreateHorzGradient(m_rectTopGradient, m_uig.GetColor(UIC_CONTROLFILL), m_uig.GetColor(UIC_CONTROLFILL));
  701. if (m_pbmBottomGradient == NULL)
  702. m_pbmBottomGradient = CBitmap::CreateHorzGradient(m_rectBottomGradient, m_uig.GetColor(UIC_CONTROLFILL), m_uig.GetColor(UIC_CONTROLFILL));
  703. }
  704. void CConfigWnd::CalcTabs()
  705. {
  706. int i, maxh = 0, lastx = 0;
  707. for (i = 0; i < GetNumElements(); i++)
  708. {
  709. ELEMENT &e = GetElement(i);
  710. CopyStr(e.tszCaption, e.didi.tszInstanceName, MAX_PATH);
  711. e.rect.left = i > 0 ? GetElement(i - 1).rect.right - 1 : 0;
  712. e.rect.top = 0;
  713. SIZE tsize = GetTextSize(e.tszCaption);
  714. e.textrect.left = e.textrect.top = 0;
  715. e.textrect.right = tsize.cx;
  716. e.textrect.bottom = tsize.cy;
  717. OffsetRect(&e.textrect, e.rect.left + TABTEXTMARGINLEFT, e.rect.top + TABTEXTMARGINTOP);
  718. int w = tsize.cx;
  719. int h = tsize.cy;
  720. e.rect.right = e.rect.left + TABTEXTMARGINLEFT + w + TABTEXTMARGINRIGHT + 1;
  721. e.rect.bottom = e.rect.top + TABTEXTMARGINTOP + h + TABTEXTMARGINBOTTOM;
  722. h = e.rect.bottom - e.rect.top;
  723. if (h > maxh) maxh = h;
  724. e.bCalc = TRUE;
  725. }
  726. for (i = 0; i < GetNumElements(); i++)
  727. {
  728. ELEMENT &e = GetElement(i);
  729. e.rect.bottom = e.rect.top + maxh;
  730. lastx = e.rect.right;
  731. }
  732. if (lastx > WINDOW_WIDTH)
  733. {
  734. if (!m_bScrollTabs)
  735. m_nLeftTab = 0;
  736. m_bScrollTabs = TRUE;
  737. }
  738. else
  739. {
  740. m_bScrollTabs = FALSE;
  741. m_nLeftTab = 0;
  742. }
  743. int cutoff = WINDOW_WIDTH;
  744. if (m_bScrollTabs)
  745. {
  746. cutoff = WINDOW_WIDTH - maxh * 2;
  747. RECT r = {WINDOW_WIDTH - maxh, 0, WINDOW_WIDTH, maxh};
  748. m_rectSTLeft = r;
  749. OffsetRect(&r, -(maxh - 1), 0);
  750. m_rectSTRight = r;
  751. }
  752. if (m_bScrollTabs && m_nLeftTab > 0)
  753. {
  754. int left = GetElement(m_nLeftTab).rect.left, right = 0;
  755. for (i = 0; i < GetNumElements(); i++)
  756. {
  757. ELEMENT &e = GetElement(i);
  758. OffsetRect(&e.rect, -left, 0);
  759. OffsetRect(&e.textrect, -left, 0);
  760. if (e.rect.right > right)
  761. right = e.rect.right;
  762. }
  763. lastx = right;
  764. }
  765. if (m_bScrollTabs)
  766. {
  767. m_bScrollTabsLeft = lastx > cutoff && m_nLeftTab < GetNumElements() - 1;
  768. m_bScrollTabsRight = m_nLeftTab > 0;
  769. }
  770. RECT t = {0/*lastx*/, 0, WINDOW_WIDTH, maxh};
  771. m_rectTopGradient = t;
  772. }
  773. void CConfigWnd::CalcButtons()
  774. {
  775. SIZE max = {0, 0};
  776. int i;
  777. for (i = 0; i < NUMBUTTONS; i++)
  778. {
  779. BUTTON &b = m_Button[i];
  780. if (!StrLen(b.tszCaption))
  781. {
  782. switch (i)
  783. {
  784. case BUTTON_RESET:
  785. LoadString(g_hModule, IDS_BUTTON_RESET, b.tszCaption, MAX_PATH);
  786. break;
  787. //@@BEGIN_MSINTERNAL
  788. #ifdef DDKBUILD
  789. case BUTTON_LAYOUT:
  790. LoadString(g_hModule, IDS_BUTTON_LAYOUT, b.tszCaption, MAX_PATH);
  791. break;
  792. #endif
  793. //@@END_MSINTERNAL
  794. case BUTTON_CANCEL:
  795. if (m_uig.InEditMode())
  796. {
  797. LoadString(g_hModule, IDS_BUTTON_CANCEL, b.tszCaption, MAX_PATH);
  798. break;
  799. }
  800. // else, intentional fallthrough
  801. case BUTTON_OK:
  802. LoadString(g_hModule, IDS_BUTTON_OK, b.tszCaption, MAX_PATH);
  803. break;
  804. }
  805. }
  806. b.textsize = GetTextSize(b.tszCaption);
  807. if (b.textsize.cx > max.cx)
  808. max.cx = b.textsize.cx;
  809. if (b.textsize.cy > max.cy)
  810. max.cy = b.textsize.cy;
  811. }
  812. max.cx += BUTTONTEXTMARGINLEFT + BUTTONTEXTMARGINRIGHT;
  813. max.cy += BUTTONTEXTMARGINTOP + BUTTONTEXTMARGINBOTTOM;
  814. m_rectBottomGradient.bottom = WINDOW_HEIGHT;
  815. m_rectBottomGradient.top = m_rectBottomGradient.bottom - max.cy - BARBUTTONMARGINTOP - BARBUTTONMARGINBOTTOM;
  816. m_rectBottomGradient.left = 0;
  817. m_rectBottomGradient.right = WINDOW_WIDTH;
  818. for (i = 0; i < NUMBUTTONS; i++)
  819. {
  820. BUTTON &b = m_Button[i];
  821. RECT z = {0,0,0,0};
  822. b.rect = z;
  823. b.rect.right = max.cx;
  824. b.rect.bottom = max.cy;
  825. int by = m_rectBottomGradient.top + BARBUTTONMARGINTOP;
  826. switch (i)
  827. {
  828. case BUTTON_RESET:
  829. OffsetRect(&b.rect, BARBUTTONMARGINLEFT, by);
  830. break;
  831. //@@BEGIN_MSINTERNAL
  832. #ifdef DDKBUILD
  833. case BUTTON_LAYOUT:
  834. OffsetRect(&b.rect, WINDOW_WIDTH / 2 - max.cx / 2, by);
  835. break;
  836. #endif
  837. //@@END_MSINTERNAL
  838. case BUTTON_CANCEL:
  839. OffsetRect(&b.rect,
  840. m_rectBottomGradient.right - BARBUTTONMARGINRIGHT - max.cx, by);
  841. break;
  842. case BUTTON_OK:
  843. OffsetRect(&b.rect,
  844. m_rectBottomGradient.right - BARBUTTONMARGINRIGHT - max.cx - max.cx - BARBUTTONSPACING, by);
  845. break;
  846. }
  847. POINT m = {(b.rect.right + b.rect.left) / 2, (b.rect.bottom + b.rect.top) / 2};
  848. b.textrect.left = m.x - b.textsize.cx / 2;
  849. b.textrect.top = m.y - b.textsize.cy / 2;
  850. b.textrect.right = b.textrect.left + b.textsize.cx;
  851. b.textrect.bottom = b.textrect.top + b.textsize.cy;
  852. }
  853. }
  854. void CConfigWnd::GetPageRect(RECT &rect, BOOL bTemp)
  855. {
  856. if (bTemp)
  857. {
  858. rect.left = 1;
  859. rect.right = WINDOW_WIDTH - 1;
  860. rect.top = 40;
  861. rect.bottom = WINDOW_HEIGHT - 40;
  862. }
  863. else
  864. {
  865. rect.left = 1;
  866. rect.right = WINDOW_WIDTH - 1;
  867. rect.top = m_rectTopGradient.bottom;
  868. rect.bottom = m_rectBottomGradient.top;
  869. }
  870. }
  871. void CConfigWnd::ToggleLayoutEditting()
  872. {
  873. m_bEditLayout = !m_bEditLayout;
  874. for (int i = 0; i < GetNumElements(); i++)
  875. {
  876. ELEMENT &e = GetElement(i);
  877. if (e.pPage)
  878. e.pPage->SetEditLayout(m_bEditLayout);
  879. }
  880. }
  881. void CConfigWnd::FireButton(int b)
  882. {
  883. switch(b)
  884. {
  885. case BUTTON_OK:
  886. if (!m_uig.InEditMode())
  887. break; // If not in edit mode, Ok button doesn't not exist so we shouldn't do anything.
  888. //@@BEGIN_MSINTERNAL
  889. #ifdef DDKBUILD
  890. if (m_uig.QueryAllowEditLayout())
  891. {
  892. int MsgBoxRet = MessageBox(m_hWnd, _T("Do you wish to save layout information?"), _T("Save"), MB_YESNOCANCEL);
  893. if (MsgBoxRet == IDYES)
  894. {
  895. // Write IHV settings for all devices.
  896. for (int i = 0; i < GetNumElements(); i++)
  897. GetElement(i).pPage->WriteIHVSetting();
  898. }
  899. else
  900. if (MsgBoxRet == IDCANCEL)
  901. break;
  902. } else
  903. #endif
  904. //@@END_MSINTERNAL
  905. Apply(); // If we are in Edit Layout mode, do not call Apply() to save to user setting.
  906. // intentional fallthrough
  907. case BUTTON_CANCEL:
  908. Destroy();
  909. break;
  910. case BUTTON_RESET:
  911. if (m_uig.InEditMode()) // Only reset if in edit mode. Do nothing in view mode.
  912. Reset();
  913. break;
  914. //@@BEGIN_MSINTERNAL
  915. #ifdef DDKBUILD
  916. case BUTTON_LAYOUT:
  917. if (m_uig.QueryAllowEditLayout())
  918. ToggleLayoutEditting();
  919. break;
  920. #endif
  921. //@@END_MSINTERNAL
  922. default:
  923. assert(0);
  924. break;
  925. }
  926. }
  927. void CConfigWnd::SelTab(int i)
  928. {
  929. if (i >= 0 && i < GetNumElements())
  930. {
  931. if (i == m_CurSel)
  932. return;
  933. ShowPage(i);
  934. HidePage(m_CurSel);
  935. m_CurSel = i;
  936. Invalidate();
  937. }
  938. }
  939. PAGETYPE *CConfigWnd::CreatePageObject(int nPage, const ELEMENT &e, HWND &refhChildWnd)
  940. {
  941. if (m_pPageFactory == NULL)
  942. return NULL;
  943. PAGETYPE *pPage = NULL;
  944. HRESULT hresult = m_pPageFactory->CreateInstance(NULL, IID_IDIDeviceActionConfigPage, (LPVOID*) &pPage);
  945. if (FAILED(hresult) || pPage == NULL)
  946. return NULL;
  947. DICFGPAGECREATESTRUCT cs;
  948. cs.dwSize = sizeof(DICFGPAGECREATESTRUCT);
  949. cs.nPage = nPage;
  950. cs.hParentWnd = m_hWnd;
  951. GetPageRect(cs.rect, TRUE);
  952. cs.hPageWnd = NULL;
  953. cs.didi = e.didi;
  954. cs.lpDID = e.lpDID;
  955. cs.pUIGlobals = &m_uig;
  956. cs.pUIFrame = dynamic_cast<IDIConfigUIFrameWindow *>(this);
  957. hresult = pPage->Create(&cs);
  958. if (FAILED(hresult))
  959. {
  960. etrace1(_T("pPage->Create() failed, returning 0x%08x\n"), hresult);
  961. pPage->Release();
  962. return NULL;
  963. }
  964. refhChildWnd = cs.hPageWnd;
  965. return pPage;
  966. }
  967. void CConfigWnd::DestroyPageObject(PAGETYPE *&pPage)
  968. {
  969. if (pPage != NULL)
  970. pPage->Release();
  971. pPage = NULL;
  972. }
  973. void CConfigWnd::ShowPage(int i)
  974. {
  975. if (i == -1)
  976. return;
  977. if (i < 0 || i >= GetNumElements())
  978. {
  979. assert(0);
  980. return;
  981. }
  982. ELEMENT &e = GetElement(i);
  983. PAGETYPE *pPage = e.pPage;
  984. if (pPage == NULL)
  985. {
  986. assert(0);
  987. return;
  988. }
  989. pPage->Show(e.GetAcFor(m_nCurGenre, e.nCurUser));
  990. }
  991. void CConfigWnd::HidePage(int i)
  992. {
  993. if (i == -1)
  994. return;
  995. if (i < 0 || i >= GetNumElements())
  996. {
  997. assert(0);
  998. return;
  999. }
  1000. PAGETYPE *pPage = GetElement(i).pPage;
  1001. if (pPage == NULL)
  1002. {
  1003. assert(0);
  1004. return;
  1005. }
  1006. pPage->Hide();
  1007. }
  1008. void CConfigWnd::OnMouseOver(POINT point, WPARAM fwKeys)
  1009. {
  1010. int i;
  1011. CFlexWnd::s_ToolTip.SetEnable(FALSE);
  1012. // check scroll tab buttons
  1013. if (m_bScrollTabs)
  1014. for (i = 0; i < 2; i++)
  1015. {
  1016. RECT &r = !i ? m_rectSTRight : m_rectSTLeft;
  1017. BOOL b = !i ? m_bScrollTabsRight : m_bScrollTabsLeft;
  1018. if (PtInRect(&r, point))
  1019. {
  1020. if (b)
  1021. GetElement(m_CurSel).pPage->SetInfoText(m_uig.InEditMode() ? IDS_INFOMSG_EDIT_TABSCROLL : IDS_INFOMSG_VIEW_TABSCROLL);
  1022. return;
  1023. }
  1024. }
  1025. // check tabs
  1026. for (i = 0; i < GetNumElements(); i++)
  1027. if (PtInRect(&(GetElement(i).rect), point))
  1028. {
  1029. GetElement(m_CurSel).pPage->SetInfoText(m_uig.InEditMode() ? IDS_INFOMSG_EDIT_TAB : IDS_INFOMSG_VIEW_TAB);
  1030. return;
  1031. }
  1032. // check buttons
  1033. for (i = 0; i < NUMBUTTONS; i++)
  1034. if (PtInRect(&(m_Button[i].rect), point))
  1035. {
  1036. switch(i)
  1037. {
  1038. case BUTTON_OK:
  1039. if (m_uig.InEditMode())
  1040. GetElement(m_CurSel).pPage->SetInfoText(IDS_INFOMSG_EDIT_OK);
  1041. break;
  1042. case BUTTON_CANCEL:
  1043. if (m_uig.InEditMode())
  1044. GetElement(m_CurSel).pPage->SetInfoText(IDS_INFOMSG_EDIT_CANCEL);
  1045. else
  1046. GetElement(m_CurSel).pPage->SetInfoText(IDS_INFOMSG_VIEW_OK);
  1047. break;
  1048. case BUTTON_RESET:
  1049. if (m_uig.InEditMode()) // Only reset if in edit mode. Do nothing in view mode.
  1050. GetElement(m_CurSel).pPage->SetInfoText(IDS_INFOMSG_EDIT_RESET);
  1051. break;
  1052. }
  1053. return;
  1054. }
  1055. GetElement(m_CurSel).pPage->SetInfoText(-1);
  1056. }
  1057. void CALLBACK CConfigWnd::TimerProc(UINT uID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2)
  1058. {
  1059. if (!IsWindow((HWND)dwUser)) return; // Verify that dwUser is a valid window handle
  1060. CConfigWnd *pCfgWnd = (CConfigWnd *)GetFlexWnd((HWND)dwUser); // Get flex object
  1061. // We use PostMessage instead of calling Render() so we stay synchronized.
  1062. PostMessage((HWND)dwUser, WM_DIRENDER, 0, 0);
  1063. }
  1064. void CConfigWnd::MapBitmaps(HDC hDC)
  1065. {
  1066. if (m_bBitmapsMapped)
  1067. return;
  1068. if (m_pbmTopGradient)
  1069. m_pbmTopGradient->MapToDC(hDC);
  1070. if (m_pbmBottomGradient)
  1071. m_pbmBottomGradient->MapToDC(hDC);
  1072. m_bBitmapsMapped = TRUE;
  1073. }
  1074. LPDIACTIONFORMATW CConfigWnd::GetCurAcFor(ELEMENT &e)
  1075. {
  1076. return e.GetAcFor(m_nCurGenre, e.nCurUser);
  1077. }
  1078. BOOL CConfigWnd::IsActionAssignedAnywhere(GUID GuidInstance, int nActionIndex)
  1079. {
  1080. // Find out which user owns the device in question first.
  1081. int nUser = 0;
  1082. for (int ii = 0; ii < GetNumElements(); ii++)
  1083. {
  1084. ELEMENT &e = GetElement(ii);
  1085. if (IsEqualGUID(e.didi.guidInstance, GuidInstance))
  1086. {
  1087. nUser = e.nCurUser;
  1088. break;
  1089. }
  1090. }
  1091. // Now we check the actions against this user.
  1092. for (int i = 0; i < GetNumElements(); i++)
  1093. {
  1094. ELEMENT &e = GetElement(i);
  1095. const LPDIACTIONFORMATW &lpAcFor = e.GetAcFor(m_nCurGenre, nUser);
  1096. if (lpAcFor == NULL)
  1097. continue;
  1098. if (nActionIndex < 0 || nActionIndex > int(lpAcFor->dwNumActions))
  1099. continue;
  1100. // If this device is not owned by this user, don't need to check.
  1101. if (e.nCurUser != nUser)
  1102. continue;
  1103. const DIACTIONW &a = lpAcFor->rgoAction[nActionIndex];
  1104. if (!IsEqualGUID(a.guidInstance, GUID_NULL))
  1105. return TRUE;
  1106. }
  1107. return FALSE;
  1108. }
  1109. LRESULT CConfigWnd::WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
  1110. {
  1111. switch (msg)
  1112. {
  1113. case WM_ACTIVATE:
  1114. switch(wParam)
  1115. {
  1116. case WA_ACTIVE:
  1117. case WA_CLICKACTIVE:
  1118. // Set the cursor extent to this window if we are in render mode because the
  1119. // cursor can't be drawn by us when it's not above us.
  1120. if (InRenderMode())
  1121. {
  1122. RECT rc;
  1123. GetWindowRect(m_hWnd, &rc);
  1124. ClipCursor(&rc);
  1125. }
  1126. // Reacquire current device
  1127. if (GetNumElements() && m_CurSel >= 0)
  1128. GetElement(m_CurSel).pPage->Reacquire();
  1129. break;
  1130. case WA_INACTIVE:
  1131. // Unacquire current device
  1132. if (GetNumElements() && m_CurSel >= 0)
  1133. GetElement(m_CurSel).pPage->Unacquire();
  1134. break;
  1135. }
  1136. break;
  1137. case WM_DIRENDER:
  1138. // Render message, sent by TimerProc() earlier.
  1139. // The timer proc has request a render operation.
  1140. Render(m_bNeedRedraw);
  1141. // Set the next timer event.
  1142. if (g_fptimeSetEvent)
  1143. g_fptimeSetEvent(20, 20, CConfigWnd::TimerProc,
  1144. (DWORD_PTR)m_hWnd, TIME_ONESHOT);
  1145. return 0;
  1146. case WM_SETFOCUS:
  1147. // Set the keyboard focus to the current page window.
  1148. ShowPage(m_CurSel); // Call Show() on current page so it can get keyboard focus.
  1149. return 0;
  1150. // WM_NCHITTEST handler is added to support moving window when in GDI mode.
  1151. case WM_NCHITTEST:
  1152. {
  1153. if (InRenderMode()) break;
  1154. BOOL bHitCaption = TRUE;
  1155. POINT point = {(short)LOWORD(lParam), (short)HIWORD(lParam)};
  1156. int i;
  1157. ScreenToClient(m_hWnd, &point);
  1158. // check scroll tab buttons
  1159. if (m_bScrollTabs)
  1160. for (i = 0; i < 2; i++)
  1161. {
  1162. RECT &r = !i ? m_rectSTRight : m_rectSTLeft;
  1163. BOOL b = !i ? m_bScrollTabsRight : m_bScrollTabsLeft;
  1164. if (PtInRect(&r, point))
  1165. {
  1166. if (b)
  1167. bHitCaption = FALSE;
  1168. break;
  1169. }
  1170. }
  1171. // check tabs
  1172. for (i = 0; i < GetNumElements(); i++)
  1173. if (PtInRect(&(GetElement(i).rect), point))
  1174. {
  1175. bHitCaption = FALSE;
  1176. break;
  1177. }
  1178. // check buttons
  1179. for (i = 0; i < NUMBUTTONS; i++)
  1180. if (PtInRect(&(m_Button[i].rect), point))
  1181. {
  1182. if ((i == BUTTON_RESET || i == BUTTON_OK) && !m_uig.InEditMode()) continue;
  1183. //@@BEGIN_MSINTERNAL
  1184. #ifdef DDKBUILD
  1185. if (i == BUTTON_LAYOUT && !m_uig.QueryAllowEditLayout()) continue;
  1186. #endif
  1187. //@@END_MSINTERNAL
  1188. bHitCaption = FALSE;
  1189. break;
  1190. }
  1191. // Check Y coordinate to see if it is within the caption bar.
  1192. if ((point.y < GetElement(0).rect.top || point.y > GetElement(0).rect.bottom) &&
  1193. (point.y < m_rectBottomGradient.top || point.y > m_rectBottomGradient.bottom))
  1194. bHitCaption = FALSE;
  1195. if (bHitCaption)
  1196. {
  1197. // If we are returning HTCAPTION, clear the page's info box.
  1198. GetElement(m_CurSel).pPage->SetInfoText(-1);
  1199. return HTCAPTION;
  1200. }
  1201. break;
  1202. }
  1203. case WM_CFGUIRESET:
  1204. {
  1205. CFlexWnd::s_ToolTip.SetEnable(FALSE);
  1206. m_bHourGlass = TRUE; // Set the flag so Render() will draw hourglass instead of arrow
  1207. Invalidate();
  1208. SendMessage(this->m_hWnd, WM_PAINT, 0, 0);
  1209. if (InRenderMode()) // If in render mode, need to specifically call OnRender as sending WM_PAINT merely changes flag.
  1210. Render(TRUE);
  1211. if (!Init(CFGWND_INIT_REINIT | CFGWND_INIT_RESET))
  1212. {
  1213. m_uig.SetFinalResult(E_FAIL);
  1214. Destroy();
  1215. }
  1216. m_bHourGlass = FALSE; // Change cursor back to arrow
  1217. m_MsgBox.Destroy();
  1218. Invalidate();
  1219. return TRUE;
  1220. }
  1221. case WM_SETCURSOR:
  1222. {
  1223. static HCURSOR hCursor = LoadCursor(NULL, IDC_ARROW);
  1224. ::SetCursor(InRenderMode() ? NULL : hCursor);
  1225. }
  1226. return TRUE;
  1227. // case WM_QUERYACTIONASSIGNEDANYWHERE:
  1228. // return IsActionAssignedAnywhere(int(wParam), int(lParam));
  1229. }
  1230. return CFlexWnd::WndProc(hWnd, msg, wParam, lParam);
  1231. }
  1232. HRESULT CConfigWnd::Apply()
  1233. {
  1234. tracescope(ts, _T("\n\nApplying Changes to All Devices...\n"));
  1235. // Devices need to be in the unaquired state when SetActionMap is called.
  1236. Unacquire();
  1237. for (int i = 0; i < GetNumElements(); i++)
  1238. GetElement(i).Apply();
  1239. Reacquire();
  1240. trace(_T("\n\n"));
  1241. return S_OK;
  1242. }
  1243. int CConfigWnd::GetNumElements()
  1244. {
  1245. return m_Element.GetSize();
  1246. }
  1247. ELEMENT &CConfigWnd::GetElement(int i)
  1248. {
  1249. if (i < 0 || i >= GetNumElements())
  1250. {
  1251. assert(0);
  1252. etrace1(_T("Tried to get invalid element %d\n"), i);
  1253. return m_InvalidElement;
  1254. }
  1255. return m_Element[i];
  1256. }
  1257. // This function returns a pointer to the action format of the device that has the given GUID
  1258. HRESULT CConfigWnd::GetActionFormatFromInstanceGuid(LPDIACTIONFORMATW *lplpAcFor, REFGUID Guid)
  1259. {
  1260. if (!lplpAcFor)
  1261. return E_INVALIDARG;
  1262. for (int i = 0; i < GetNumElements(); i++)
  1263. {
  1264. ELEMENT &e = m_Element[i];
  1265. if (e.didi.guidInstance == Guid)
  1266. {
  1267. *lplpAcFor = GetCurAcFor(e);
  1268. return S_OK;
  1269. }
  1270. }
  1271. return E_INVALIDARG;
  1272. }
  1273. HDC CConfigWnd::GetRenderDC()
  1274. {
  1275. assert(InRenderMode());
  1276. if (m_bRender3D)
  1277. return m_pbm3D == NULL ? NULL : m_pbm3D->BeginPaintInto();
  1278. else
  1279. {
  1280. if (m_pSurface == NULL)
  1281. return NULL;
  1282. HDC hDC = NULL;
  1283. HRESULT hr = m_pSurface->GetDC(&hDC);
  1284. if (FAILED(hr))
  1285. if (hr == DDERR_SURFACELOST)
  1286. {
  1287. m_pSurface->Restore(); // Restore the surface
  1288. hr = m_pSurface->GetDC(&hDC); // Retry
  1289. if (FAILED(hr))
  1290. return NULL;
  1291. }
  1292. else
  1293. return NULL;
  1294. return hDC;
  1295. }
  1296. }
  1297. void CConfigWnd::ReleaseRenderDC(HDC &phDC)
  1298. {
  1299. assert(InRenderMode());
  1300. HDC hDC = phDC;
  1301. phDC = NULL;
  1302. if (m_bRender3D)
  1303. {
  1304. if (m_pbm3D == NULL)
  1305. return;
  1306. m_pbm3D->EndPaintInto(hDC);
  1307. }
  1308. else
  1309. {
  1310. if (m_pSurface == NULL)
  1311. return;
  1312. m_pSurface->ReleaseDC(hDC);
  1313. }
  1314. }
  1315. struct BITMAPINFO_3MASKS
  1316. {
  1317. BITMAPINFOHEADER bmiHeader;
  1318. RGBQUAD bmiColors[3];
  1319. };
  1320. void CConfigWnd::Create3DBitmap()
  1321. {
  1322. HDC hDC = CreateCompatibleDC(NULL);
  1323. BITMAPINFO_3MASKS bmi3mask; // BITMAPINFO with 3 DWORDs for bmiColors
  1324. BITMAPINFO *pbmi = (BITMAPINFO*)&bmi3mask;
  1325. BITMAPINFOHEADER &h = pbmi->bmiHeader;
  1326. h.biSize = sizeof(BITMAPINFOHEADER);
  1327. h.biWidth = WINDOW_WIDTH;
  1328. h.biHeight = -WINDOW_HEIGHT;
  1329. h.biPlanes = 1;
  1330. h.biSizeImage = 0;
  1331. h.biXPelsPerMeter = 100;
  1332. h.biYPelsPerMeter = 100;
  1333. h.biClrImportant = 0;
  1334. // Get the surface's pixel format
  1335. D3DSURFACE_DESC d3dsd;
  1336. ZeroMemory(&d3dsd, sizeof(d3dsd));
  1337. m_pSurface3D->GetDesc(&d3dsd);
  1338. m_SurfFormat = d3dsd.Format;
  1339. switch(d3dsd.Format)
  1340. {
  1341. case D3DFMT_R5G6B5:
  1342. h.biClrUsed = 3;
  1343. h.biBitCount = 16;
  1344. m_uiPixelSize = 2;
  1345. h.biCompression = BI_BITFIELDS;
  1346. *((LPDWORD)pbmi->bmiColors) = 0xF800;
  1347. *((LPDWORD)pbmi->bmiColors+1) = 0x07E0;
  1348. *((LPDWORD)pbmi->bmiColors+2) = 0x001F;
  1349. break;
  1350. case D3DFMT_X1R5G5B5:
  1351. case D3DFMT_A1R5G5B5:
  1352. h.biClrUsed = 3;
  1353. h.biBitCount = 16;
  1354. m_uiPixelSize = 2;
  1355. h.biCompression = BI_BITFIELDS;
  1356. *((LPDWORD)pbmi->bmiColors) = 0x7C00;
  1357. *((LPDWORD)pbmi->bmiColors+1) = 0x03E0;
  1358. *((LPDWORD)pbmi->bmiColors+2) = 0x001F;
  1359. break;
  1360. case D3DFMT_R8G8B8:
  1361. h.biClrUsed = 0;
  1362. h.biBitCount = 24;
  1363. m_uiPixelSize = 3;
  1364. h.biCompression = BI_RGB;
  1365. break;
  1366. case D3DFMT_A8R8G8B8:
  1367. case D3DFMT_X8R8G8B8:
  1368. default:
  1369. // Use 32 bits for all other formats
  1370. h.biClrUsed = 0;
  1371. h.biBitCount = 32;
  1372. m_uiPixelSize = 4;
  1373. h.biCompression = BI_RGB;
  1374. break;
  1375. }
  1376. HBITMAP hbm = CreateDIBSection(
  1377. hDC,
  1378. pbmi,
  1379. DIB_RGB_COLORS,
  1380. &m_p3DBits,
  1381. NULL,
  1382. 0);
  1383. DeleteDC(hDC);
  1384. hDC = NULL;
  1385. if (hbm != NULL)
  1386. m_pbm3D = CBitmap::StealToCreate(hbm);
  1387. if (hbm != NULL)
  1388. DeleteObject((HGDIOBJ)hbm);
  1389. hbm = NULL;
  1390. }
  1391. void CConfigWnd::Copy3DBitmapToSurface3D()
  1392. {
  1393. assert(m_bRender3D);
  1394. if (m_p3DBits == NULL || m_pbm3D == NULL || m_pSurface3D == NULL)
  1395. {
  1396. etrace(_T("One or more of the vars required for Copy3DBitmapToSurface() was NULL!\n"));
  1397. return;
  1398. }
  1399. RECT rect = {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT};
  1400. HRESULT hr = D3DXLoadSurfaceFromMemory(
  1401. m_pSurface3D,
  1402. NULL,
  1403. NULL,//&rect,
  1404. m_p3DBits,
  1405. m_SurfFormat,
  1406. WINDOW_WIDTH * m_uiPixelSize,
  1407. NULL,
  1408. &rect,
  1409. D3DX_FILTER_POINT,
  1410. 0); // Disable Color Key
  1411. }
  1412. void CConfigWnd::CallRenderCallback()
  1413. {
  1414. LPDICONFIGUREDEVICESCALLBACK pCallback = m_uig.GetCallback();
  1415. LPVOID pvRefData = m_uig.GetRefData();
  1416. if (pCallback == NULL)
  1417. return;
  1418. if (m_bRender3D)
  1419. {
  1420. Copy3DBitmapToSurface3D();
  1421. pCallback(m_pSurface3D, pvRefData);
  1422. }
  1423. else
  1424. {
  1425. pCallback(m_pSurface, pvRefData);
  1426. }
  1427. }
  1428. void CConfigWnd::OnRender(BOOL bInternalCall)
  1429. {
  1430. m_bNeedRedraw = TRUE;
  1431. }
  1432. void CConfigWnd::Render(BOOL bInternalCall)
  1433. {
  1434. tracescope(__ts, _T("CConfigWnd::Render() "));
  1435. traceBOOL(bInternalCall);
  1436. m_bNeedRedraw = FALSE;
  1437. ValidateRect(m_hWnd, NULL);
  1438. if (m_hWnd == NULL)
  1439. return;
  1440. HDC hDC = GetRenderDC();
  1441. if (hDC == NULL)
  1442. return;
  1443. if (bInternalCall)
  1444. RenderInto(hDC);
  1445. static ICONINFO IconInfo;
  1446. static HCURSOR hOldCursor = NULL;
  1447. static HCURSOR hCursor;
  1448. if (m_bHourGlass)
  1449. hCursor = LoadCursor(NULL, IDC_WAIT);
  1450. else
  1451. hCursor = LoadCursor(NULL, IDC_ARROW);
  1452. if (hCursor == NULL)
  1453. return;
  1454. if (hOldCursor != hCursor)
  1455. {
  1456. hOldCursor = hCursor;
  1457. GetIconInfo(hCursor, &IconInfo);
  1458. if (IconInfo.hbmMask)
  1459. DeleteObject(IconInfo.hbmMask);
  1460. if (IconInfo.hbmColor)
  1461. DeleteObject(IconInfo.hbmColor);
  1462. }
  1463. POINT pt;
  1464. GetCursorPos(&pt);
  1465. ScreenToClient(m_hWnd, &pt);
  1466. pt.x -= IconInfo.xHotspot;
  1467. pt.y -= IconInfo.yHotspot;
  1468. if (m_pbmPointerEraser)
  1469. m_pbmPointerEraser->Get(hDC, pt);
  1470. // If m_bHourGlass is true, we are resetting, so we don't draw mouse cursor.
  1471. if (hCursor && !m_bHourGlass)
  1472. DrawIcon(hDC, pt.x, pt.y, hCursor);
  1473. ReleaseRenderDC(hDC);
  1474. CallRenderCallback();
  1475. hDC = GetRenderDC();
  1476. if (hDC == NULL)
  1477. return;
  1478. if (m_pbmPointerEraser)
  1479. m_pbmPointerEraser->Draw(hDC, pt);
  1480. ReleaseRenderDC(hDC);
  1481. }
  1482. void CConfigWnd::Unacquire()
  1483. {
  1484. for (int i = 0; i < GetNumElements(); i++)
  1485. {
  1486. ELEMENT &e = m_Element[i];
  1487. if (e.pPage != NULL)
  1488. e.pPage->Unacquire();
  1489. }
  1490. }
  1491. void CConfigWnd::Reacquire()
  1492. {
  1493. for (int i = 0; i < GetNumElements(); i++)
  1494. {
  1495. ELEMENT &e = m_Element[i];
  1496. if (e.pPage != NULL)
  1497. e.pPage->Reacquire();
  1498. }
  1499. }
  1500. HRESULT CConfigWnd::Reset()
  1501. {
  1502. RECT rect;
  1503. int iCenterX, iCenterY;
  1504. GetClientRect(&rect);
  1505. iCenterX = (rect.left + rect.right) >> 1;
  1506. iCenterY = (rect.top + rect.bottom) >> 1;
  1507. rect.left = rect.right = iCenterX;
  1508. rect.top = rect.bottom = iCenterY;
  1509. InflateRect(&rect, g_iResetMsgBoxWidth >> 1, g_iResetMsgBoxHeight >> 1);
  1510. m_MsgBox.Create(m_hWnd, rect, FALSE);
  1511. m_MsgBox.SetNotify(m_hWnd);
  1512. m_MsgBox.SetFont((HFONT)m_uig.GetFont(UIE_USERNAMES));
  1513. m_MsgBox.SetColors(m_uig.GetTextColor(UIE_USERNAMES),
  1514. m_uig.GetBkColor(UIE_USERNAMES),
  1515. m_uig.GetTextColor(UIE_USERNAMESEL),
  1516. m_uig.GetBkColor(UIE_USERNAMESEL),
  1517. m_uig.GetBrushColor(UIE_USERNAMES),
  1518. m_uig.GetPenColor(UIE_USERNAMES));
  1519. TCHAR tszResourceString[MAX_PATH];
  1520. LoadString(g_hModule, IDS_RESETMSG, tszResourceString, MAX_PATH);
  1521. m_MsgBox.SetText(tszResourceString);
  1522. ::ShowWindow(m_MsgBox.m_hWnd, SW_SHOW);
  1523. ::SetWindowPos(m_MsgBox.m_hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_SHOWWINDOW);
  1524. m_MsgBox.Invalidate();
  1525. return S_OK;
  1526. }
  1527. HRESULT CConfigWnd::QueryActionAssignedAnywhere(GUID GuidInstance, int i)
  1528. {
  1529. return IsActionAssignedAnywhere(GuidInstance, i) ? S_OK : S_FALSE;
  1530. }
  1531. int CConfigWnd::GetNumGenres()
  1532. {
  1533. return m_uig.GetNumMasterAcFors();
  1534. }
  1535. HRESULT CConfigWnd::SetCurUser(int nPage, int nUser)
  1536. {
  1537. // make sure we're using a valid element index
  1538. if (nPage < 0 || nPage >= GetNumElements())
  1539. {
  1540. assert(0);
  1541. return E_FAIL;
  1542. }
  1543. // get the element
  1544. ELEMENT &e = GetElement(nPage);
  1545. // don't do anything if we're already set to this user
  1546. if (e.nCurUser == nUser)
  1547. return S_OK;
  1548. // store new curuser
  1549. e.nCurUser = nUser;
  1550. // if this page isn't the one currently shown, do nothing
  1551. // (it'll get the new acfor when it's shown)
  1552. if (m_CurSel != nPage)
  1553. return S_OK;
  1554. // otherwised, cycle the page to reflect change
  1555. if (e.pPage)
  1556. e.pPage->Unacquire();
  1557. HidePage(nPage);
  1558. ShowPage(nPage);
  1559. if (e.pPage)
  1560. e.pPage->Reacquire();
  1561. return S_OK;
  1562. }
  1563. HRESULT CConfigWnd::SetCurGenre(int NewGenre)
  1564. {
  1565. // if no change, do nothing
  1566. if (NewGenre == m_nCurGenre)
  1567. return S_OK;
  1568. // make sure genre index is in range
  1569. if (NewGenre < 0 || NewGenre >= GetNumGenres())
  1570. return E_INVALIDARG;
  1571. // set genre
  1572. m_nCurGenre = NewGenre;
  1573. // store which page is currently up
  1574. int iOldPage = m_CurSel;
  1575. // for each page...
  1576. BOOL bShown = FALSE;
  1577. for (int i = 0; i < GetNumElements(); i++)
  1578. {
  1579. ELEMENT &e = GetElement(i);
  1580. // hide the page and unacquire its device
  1581. if (e.pPage)
  1582. {
  1583. e.pPage->Unacquire();
  1584. HidePage(i);
  1585. }
  1586. // show page if it was the old cur page
  1587. if (i == iOldPage && e.pPage && GetCurAcFor(e))
  1588. {
  1589. ShowPage(i);
  1590. bShown = TRUE;
  1591. }
  1592. // reacquire device
  1593. if (e.pPage)
  1594. e.pPage->Reacquire();
  1595. }
  1596. // if nothing was shown, show something
  1597. if (!bShown && GetNumElements() > 0)
  1598. {
  1599. m_CurSel = -1;
  1600. SelTab(0);
  1601. }
  1602. // if we showed the one we expected to show, we succeeded
  1603. return bShown ? S_OK : E_FAIL;
  1604. }
  1605. int CConfigWnd::GetCurGenre()
  1606. {
  1607. return m_nCurGenre;
  1608. }
  1609. HWND CConfigWnd::GetMainHWND()
  1610. {
  1611. return m_hWnd;
  1612. }
  1613. // This is called by CDIDeviceActionConfigPage::DeviceUINotify.
  1614. // We scan the ELEMENT array and when we find a match, destroy and recreate the device
  1615. // object, then return it back to CDIDeviceActionConfigPage so it can update its pointer.
  1616. LPDIRECTINPUTDEVICE8W CConfigWnd::RenewDevice(GUID &GuidInstance)
  1617. {
  1618. for (int i = 0; i < GetNumElements(); i++)
  1619. {
  1620. ELEMENT &e = GetElement(i);
  1621. if (e.didi.guidInstance == GuidInstance)
  1622. {
  1623. // Releaes the instance we have
  1624. if (e.lpDID)
  1625. {
  1626. e.lpDID->Release();
  1627. e.lpDID = NULL;
  1628. }
  1629. // Recreate the device
  1630. e.lpDID = CreateDevice(e.didi.guidInstance);
  1631. return e.lpDID;
  1632. }
  1633. }
  1634. return NULL;
  1635. }
  1636. LPDIACTIONFORMATW ELEMENT::GetAcFor(int nGenre, int nUser, BOOL bHwDefault)
  1637. {
  1638. // return null if requesting for unassigned user
  1639. if (nUser == -1)
  1640. return NULL;
  1641. // validate params
  1642. if (!lpDID || !pUIGlobals || nGenre < 0 ||
  1643. nGenre >= pUIGlobals->GetNumMasterAcFors() ||
  1644. nUser < 0 || nUser >= pUIGlobals->GetNumUserNames())
  1645. {
  1646. etrace(_T("ELEMENT::GetAcFor(): Invalid params\n"));
  1647. return NULL;
  1648. }
  1649. // generate dword id for map entry
  1650. DWORD dwMap = GENREUSER2MAP(nGenre, nUser);
  1651. // try to get that acfor
  1652. LPDIACTIONFORMATW lpAcFor = NULL;
  1653. BOOL bFound = AcForMap.Lookup(dwMap, lpAcFor);
  1654. // if we found it and its not null and we are asked for hardware default setting, return it
  1655. if (bFound && lpAcFor && !bHwDefault)
  1656. return lpAcFor;
  1657. // otherwise... we gotta make it
  1658. tracescope(__ts, _T("ELEMENT::GetAcFor"));
  1659. trace2(_T("(%d, %d)\n"), nGenre, nUser);
  1660. trace1(_T("Building map entry 0x%08x...\n"), dwMap);
  1661. // copy it from the masteracfor for the genre
  1662. lpAcFor = DupActionFormat(&(pUIGlobals->RefMasterAcFor(nGenre)));
  1663. if (!lpAcFor)
  1664. {
  1665. etrace(_T("DupActionFormat() failed\n"));
  1666. return NULL;
  1667. }
  1668. // build it for the user
  1669. DWORD dwFlags = 0;
  1670. if (bHwDefault
  1671. //@@BEGIN_MSINTERNAL
  1672. #ifdef DDKBUILD
  1673. || pUIGlobals->QueryAllowEditLayout()
  1674. #endif
  1675. //@@END_MSINTERNAL
  1676. )
  1677. dwFlags |= DIDBAM_HWDEFAULTS;
  1678. LPCWSTR wszUserName = pUIGlobals->GetUserName(nUser);
  1679. HRESULT hr = lpDID->BuildActionMap(lpAcFor, wszUserName, dwFlags);
  1680. if (FAILED(hr))
  1681. {
  1682. etrace4(_T("BuildActionMap(0x%p, %s, 0x%08x) failed, returning 0x%08x\n"), lpAcFor, QSAFESTR(wszUserName), dwFlags, hr);
  1683. FreeActionFormatDup(lpAcFor);
  1684. lpAcFor = NULL;
  1685. return NULL;
  1686. }
  1687. else
  1688. {
  1689. trace3(_T("BuildActionMap(0x%p, %s, 0x%08x) succeeded\n"), lpAcFor, QSAFESTR(wszUserName), dwFlags);
  1690. // Now we check if the return code is DI_WRITEPROTECT. If so, device can't be remapped.
  1691. if (hr == DI_WRITEPROTECT)
  1692. {
  1693. // The way we disable mapping is to add DIA_APPFIXED flag to all actions.
  1694. for (DWORD i = 0; i < lpAcFor->dwNumActions; ++i)
  1695. lpAcFor->rgoAction[i].dwFlags |= DIA_APPFIXED;
  1696. }
  1697. }
  1698. // Here we copy the DIA_APPFIXED flag back to our action format for all DIACTION that had this.
  1699. const DIACTIONFORMATW &MasterAcFor = pUIGlobals->RefMasterAcFor(nGenre);
  1700. for (DWORD i = 0; i < MasterAcFor.dwNumActions; ++i)
  1701. if (MasterAcFor.rgoAction[i].dwFlags & DIA_APPFIXED)
  1702. lpAcFor->rgoAction[i].dwFlags |= DIA_APPFIXED;
  1703. // set it in the map
  1704. assert(lpAcFor != NULL);
  1705. AcForMap.SetAt(dwMap, lpAcFor);
  1706. // return it
  1707. return lpAcFor;
  1708. }
  1709. void ELEMENT::FreeMap()
  1710. {
  1711. POSITION pos = AcForMap.GetStartPosition();
  1712. while (pos != NULL)
  1713. {
  1714. DWORD dwMap = (DWORD)-1;
  1715. LPDIACTIONFORMATW lpAcFor = NULL;
  1716. AcForMap.GetNextAssoc(pos, dwMap, lpAcFor);
  1717. if (lpAcFor)
  1718. FreeActionFormatDup(lpAcFor);
  1719. }
  1720. AcForMap.RemoveAll();
  1721. }
  1722. void ELEMENT::Apply()
  1723. {
  1724. tracescope(tsa, _T("\nELEMENT::Apply()\n"));
  1725. trace1(_T("Applying Changes to Device %s\n"), QSAFESTR(didi.tszInstanceName));
  1726. if (lpDID == NULL)
  1727. {
  1728. etrace(_T("NULL lpDID, can't apply\n"));
  1729. return;
  1730. }
  1731. if (pUIGlobals == NULL)
  1732. {
  1733. etrace(_T("NULL pUIGlobals, can't apply\n"));
  1734. return;
  1735. }
  1736. LPDIACTIONFORMATW lpAcFor = NULL;
  1737. // go through the map and add the map keys to last if the user
  1738. // is the current user assignment, or to first if not
  1739. CList<DWORD, DWORD &> first, last;
  1740. POSITION pos = AcForMap.GetStartPosition();
  1741. while (pos != NULL)
  1742. {
  1743. DWORD dwMap = (DWORD)-1;
  1744. lpAcFor = NULL;
  1745. AcForMap.GetNextAssoc(pos, dwMap, lpAcFor);
  1746. if (MAP2USER(dwMap) == nCurUser)
  1747. last.AddTail(dwMap);
  1748. else
  1749. first.AddTail(dwMap);
  1750. }
  1751. // concatenate lists
  1752. first.AddTail(&last);
  1753. // now go through the resulting list (so that the current
  1754. // assignments are set last) if this device is assigned.
  1755. if (nCurUser != -1)
  1756. {
  1757. pos = first.GetHeadPosition();
  1758. while (pos != NULL)
  1759. {
  1760. DWORD dwMap = first.GetNext(pos);
  1761. lpAcFor = AcForMap[dwMap];
  1762. tracescope(tsa2, _T("Applying lpAcFor at AcForMap["));
  1763. trace1(_T("0x%08x]...\n"), dwMap);
  1764. if (lpAcFor == NULL)
  1765. {
  1766. etrace(_T("NULL lpAcFor, can't apply\n"));
  1767. continue;
  1768. }
  1769. int nGenre = MAP2GENRE(dwMap);
  1770. int nUser = MAP2USER(dwMap);
  1771. LPCWSTR wszUserName = pUIGlobals->GetUserName(nUser);
  1772. traceLONG(nGenre);
  1773. traceLONG(nUser);
  1774. traceWSTR(wszUserName);
  1775. TraceActionFormat(_T("Final Device ActionFormat:"), *lpAcFor);
  1776. for (DWORD j = 0; j < lpAcFor->dwNumActions; ++j)
  1777. {
  1778. if( lpAcFor->rgoAction[j].dwObjID == (DWORD)-1 || IsEqualGUID(lpAcFor->rgoAction[j].guidInstance, GUID_NULL))
  1779. {
  1780. lpAcFor->rgoAction[j].dwHow = DIAH_UNMAPPED;
  1781. }
  1782. else if( lpAcFor->rgoAction[j].dwHow &
  1783. ( DIAH_USERCONFIG | DIAH_APPREQUESTED | DIAH_HWAPP | DIAH_HWDEFAULT | DIAH_DEFAULT ) )
  1784. {
  1785. //@@BEGIN_MSINTERNAL
  1786. // ISSUE-2001/03/27-MarcAnd should look at doing this less destructively
  1787. // that is if everything is defaults then leave them alon
  1788. //@@END_MSINTERNAL
  1789. lpAcFor->rgoAction[j].dwHow = DIAH_USERCONFIG;
  1790. }
  1791. else if(IsEqualGUID(didi.guidInstance,lpAcFor->rgoAction[j].guidInstance))
  1792. {
  1793. lpAcFor->rgoAction[j].dwHow = DIAH_USERCONFIG;
  1794. }
  1795. }
  1796. HRESULT hr;
  1797. hr = lpDID->SetActionMap(lpAcFor, wszUserName, DIDSAM_FORCESAVE|DIDSAM_DEFAULT);
  1798. if (FAILED(hr))
  1799. etrace1(_T("SetActionMap() failed, returning 0x%08x\n"), hr);
  1800. else
  1801. trace(_T("SetActionMap() succeeded\n"));
  1802. }
  1803. } // if (nCurUser != -1)
  1804. else
  1805. {
  1806. // we're unassigned, set null
  1807. trace(_T("Unassigning...\n"));
  1808. // we need an acfor to unassign, so get one if don't have
  1809. // one left over from what we just did
  1810. if (!lpAcFor)
  1811. lpAcFor = GetAcFor(0, 0);
  1812. if (!lpAcFor)
  1813. etrace(_T("Couldn't get an acfor for unassignment\n"));
  1814. HRESULT hr;
  1815. hr = lpDID->SetActionMap(lpAcFor, NULL, DIDSAM_NOUSER);
  1816. if (FAILED(hr))
  1817. etrace1(_T("SetActionMap() failed, returning 0x%08x\n"), hr);
  1818. else
  1819. trace(_T("SetActionMap() succeeded\n"));
  1820. }
  1821. }
  1822. int CConfigWnd::GetNumUsers()
  1823. {
  1824. return m_uig.GetNumUserNames();
  1825. }
  1826. int CConfigWnd::GetCurUser(int nPage)
  1827. {
  1828. return GetElement(nPage).nCurUser;
  1829. }