home *** CD-ROM | disk | FTP | other *** search
/ Beginning Direct3D Game Programming / Direct3D.iso / directx / dxf / samples / multimedia / directinput / diconfig / configwnd.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2000-09-22  |  46.4 KB  |  2,033 lines

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