|
|
//-----------------------------------------------------------------------------
// File: configwnd.cpp
//
// Desc: CConfigWnd is derived from CFlexWnd. It implements the top-level
// UI window which all other windows are descendents of.
//
// Functionalities handled by CConfigWnd are device tabs, Reset, Ok,
// and Cancel buttons.
//
// Copyright (C) 1999-2000 Microsoft Corporation. All Rights Reserved.
//-----------------------------------------------------------------------------
#include "common.hpp"
LPCTSTR g_tszAppWindowName = _T("DINPUT Default Mapper UI");
const int WINDOW_WIDTH = 640; const int WINDOW_HEIGHT = 480; const int TABTEXTMARGINLEFT = 7; const int TABTEXTMARGINTOP = 3; const int TABTEXTMARGINRIGHT = 7; const int TABTEXTMARGINBOTTOM = 4; const int BUTTONTEXTMARGINLEFT = 7; const int BUTTONTEXTMARGINTOP = 3; const int BUTTONTEXTMARGINRIGHT = 7; const int BUTTONTEXTMARGINBOTTOM = 4; const int BARBUTTONMARGINLEFT = 9; const int BARBUTTONMARGINTOP = 4; const int BARBUTTONMARGINRIGHT = 9; const int BARBUTTONMARGINBOTTOM = 5; const int BARBUTTONSPACING = 4;
//#define WM_QUERYACTIONASSIGNEDANYWHERE (WM_USER + 4)
CConfigWnd::CConfigWnd(CUIGlobals &uig) : m_uig(uig), m_bCreated(FALSE), m_pPageFactory(NULL), m_hPageFactoryInst(NULL), m_pSurface(NULL), m_pSurface3D(NULL), //@@BEGIN_MSINTERNAL
#ifdef DDKBUILD
m_bEditLayout(uig.QueryAllowEditLayout()), #endif
//@@END_MSINTERNAL
m_CurSel(-1), m_nCurGenre(0), m_pbmTopGradient(NULL), m_pbmBottomGradient(NULL), m_pbmPointerEraser(NULL), m_pbm3D(NULL), m_p3DBits(NULL), m_SurfFormat(D3DFMT_UNKNOWN), m_uiPixelSize(4), m_bBitmapsMapped(FALSE), m_lpDI(NULL), m_bScrollTabs(FALSE), m_bScrollTabsLeft(FALSE), m_bScrollTabsRight(FALSE), m_nLeftTab(0), m_dwInitFlags(0), m_bHourGlass(FALSE), m_bNeedRedraw(FALSE) { tracescope(__ts, _T("CConfigWnd::CConfigWnd()\n")); m_lpDI = m_uig.GetDI();
m_pSurface = m_uig.GetSurface(); m_pSurface3D = m_uig.GetSurface3D();
if (m_pSurface != NULL || m_pSurface3D != NULL) { if (m_pSurface != NULL && m_pSurface3D != NULL) { etrace(_T("Both Surface and Surface3D are non-NULL, will use only Surface3D\n")); m_pSurface->Release(); m_pSurface = NULL;
assert(m_pSurface3D != NULL); assert(m_pSurface == NULL); }
assert(m_pSurface != NULL || m_pSurface3D != NULL); assert(!(m_pSurface != NULL && m_pSurface3D != NULL));
m_bRender3D = (m_pSurface3D != NULL);
SetRenderMode(); trace(_T("RenderMode set\n")); traceBOOL(m_bRender3D);
if (m_bRender3D) Create3DBitmap();
HDC hDC = GetRenderDC(); if (hDC != NULL) { m_pbmPointerEraser = CBitmap::Create( GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), hDC);
ReleaseRenderDC(hDC); } else etrace(_T("Failed to get Render DC")); } }
CConfigWnd::~CConfigWnd() { tracescope(__ts, _T("CConfigWnd::~CConfigWnd()\n")); ClearList();
if (m_lpDI != NULL) m_lpDI->Release(); m_lpDI = NULL;
if (m_pSurface != NULL) m_pSurface->Release(); m_pSurface = NULL;
if (m_pSurface3D != NULL) m_pSurface3D->Release(); m_pSurface3D = NULL;
if (m_pPageFactory != NULL) m_pPageFactory->Release(); m_pPageFactory = NULL;
if (m_hPageFactoryInst != NULL) FreeLibrary(m_hPageFactoryInst); m_hPageFactoryInst = NULL;
if (m_pbmPointerEraser != NULL) delete m_pbmPointerEraser; m_pbmPointerEraser = NULL;
if (m_pbm3D != NULL) delete m_pbm3D; m_pbm3D = NULL;
if (m_pbmTopGradient != NULL) delete m_pbmTopGradient; m_pbmTopGradient = NULL;
if (m_pbmBottomGradient != NULL) delete m_pbmBottomGradient; m_pbmBottomGradient = NULL; }
HWND CMouseTrap::Create(HWND hParent, BOOL bInRenderMode) { if (m_hWnd) return m_hWnd;
m_hParent = hParent; int sx = GetSystemMetrics(SM_CXSCREEN); int sy = GetSystemMetrics(SM_CYSCREEN); RECT rect = {0, 0, sx, sy};
// If we are not in render mode, the trap window is exactly the same as the parent window
if (!bInRenderMode) GetWindowRect(hParent, &rect);
return CFlexWnd::Create( hParent, NULL, WS_EX_TOPMOST, WS_POPUP | WS_VISIBLE, rect); }
BOOL CConfigWnd::Create(HWND hParent) { tracescope(__ts, _T("CConfigWnd::Create()\n")); traceHEX(hParent);
HRESULT hresult = PrivGetClassObject(CLSID_CDIDeviceActionConfigPage, CLSCTX_INPROC_SERVER, NULL, IID_IClassFactory, (LPVOID*) &m_pPageFactory, &m_hPageFactoryInst); if (FAILED(hresult)) { // TODO: indicate failure to create page factory
m_pPageFactory = NULL; m_hPageFactoryInst = NULL; etrace1(_T("Failed to create page classfactory, PrivGetClassObject() returned 0x%08x\n"), hresult); return FALSE; }
int sx = GetSystemMetrics(SM_CXSCREEN); int sy = GetSystemMetrics(SM_CYSCREEN); int w = WINDOW_WIDTH; int h = WINDOW_HEIGHT; int rx = sx - w; int ry = sy - h; RECT rect = {rx / 2, ry / 2, 0, 0}; rect.right = rect.left + w; rect.bottom = rect.top + h;
HWND hConfigParent = hParent;
if (InRenderMode()) { hConfigParent = m_MouseTrap.Create(hParent, InRenderMode()); if (hConfigParent == NULL) hConfigParent = hParent; }
HWND hRet = CFlexWnd::Create( hConfigParent, g_tszAppWindowName, 0, WS_POPUP | WS_VISIBLE | WS_CLIPCHILDREN, rect);
if (hRet == NULL) etrace(_T("CFlexWnd::Create() failed!\n"));
// Set the cursor extent to this window if we are in render mode (full-screen)
if (InRenderMode()) { RECT rc; GetWindowRect(m_hWnd, &rc); ClipCursor(&rc); }
return NULL != hRet; }
void CConfigWnd::SetForegroundWindow() { // find the window
HWND hWnd = FindWindow(GetDefaultClassName(), g_tszAppWindowName);
// activate it if found
if (NULL != hWnd) ::SetForegroundWindow(hWnd); }
void CConfigWnd::OnPaint(HDC hDC) { if (hDC == NULL) return;
SIZE topsize = GetRectSize(m_rectTopGradient); SIZE bottomsize = GetRectSize(m_rectBottomGradient); SIZE bsize = {max(topsize.cx, bottomsize.cx), max(topsize.cy, bottomsize.cy)}; CBitmap *pbm = CBitmap::Create(bsize, hDC); if (pbm == NULL) return; HDC hBDC = NULL, hODC = hDC; if (m_bHourGlass) { if (!InRenderMode()) { // If not in fullscreen mode, change cursor to hourglass
HCURSOR hCursor; hCursor = LoadCursor(NULL, IDC_WAIT); SetCursor(hCursor); } else { // If in fullscreen mode, hide the cursor during reset process.
SetCursor(NULL); } }
hBDC = pbm->BeginPaintInto(hDC); if (hBDC == NULL) { delete pbm; return; } hDC = hBDC;
if (m_pbmTopGradient != NULL) m_pbmTopGradient->Draw(hDC);
{ CPaintHelper ph(m_uig, hDC);
ph.SetElement(UIE_BORDER);
ph.MoveTo(0, m_rectTopGradient.bottom - 1); ph.LineTo(WINDOW_WIDTH, m_rectTopGradient.bottom - 1);
int i; for (i = 0; i < GetNumElements(); i++) { const ELEMENT &e = GetElement(i); BOOL bSel = i == m_CurSel;
ph.SetElement(bSel ? UIE_SELTAB : UIE_TAB);
ph.Rectangle(e.rect); RECT trect = e.textrect; DrawText(hDC, e.tszCaption, -1, &trect, DT_NOCLIP | DT_NOPREFIX);
if (bSel) { ph.SetPen(UIP_BLACK);
ph.MoveTo(e.rect.left + 1, e.rect.bottom - 1); ph.LineTo(e.rect.right - 1, e.rect.bottom - 1); } }
if (m_bScrollTabs && GetNumElements() > 0) { ph.SetElement(UIE_TABARROW);
const ELEMENT &e = GetElement(0); int h = e.rect.bottom - e.rect.top;
for (i = 0; i < 2; i++) { RECT &rect = i == 0 ? m_rectSTRight : m_rectSTLeft; BOOL bDraw = i ? m_bScrollTabsLeft : m_bScrollTabsRight; ph.Rectangle(rect); if (!bDraw) continue;
int d,l,r,m,t,b, f = !i, w; w = rect.right - rect.left;
l = f ? w / 4 : 3 * w / 8; r = f ? 5 * w / 8 : 3 * w / 4; d = r - l; m = w / 2; t = m - d; b = m + d;
l += rect.left; r += rect.left;
POINT p[4]; p[3].x = p[0].x = f ? l : r; p[2].x = p[1].x = f ? r : l; p[3].y = p[0].y = m; p[1].y = t; p[2].y = b;
Polyline(hDC, p, 4); } } }
pbm->Draw(hODC, topsize); m_pbmBottomGradient->Draw(hDC);
{ CPaintHelper ph(m_uig, hDC);
ph.SetElement(UIE_BORDER);
Rectangle(hDC, 0, -1, WINDOW_WIDTH, GetRectSize(m_rectBottomGradient).cy);
for (int i = 0; i < NUMBUTTONS; i++) { BOOL bOkOnly = !m_uig.InEditMode(); const BUTTON &b = m_Button[i];
//@@BEGIN_MSINTERNAL
#ifdef DDKBUILD
BOOL bLayoutButton = i == BUTTON_LAYOUT;
if (!m_uig.QueryAllowEditLayout() && bLayoutButton) continue; #endif
//@@END_MSINTERNAL
if ( bOkOnly && i != BUTTON_CANCEL //@@BEGIN_MSINTERNAL
#ifdef DDKBUILD
&& !bLayoutButton #endif
//@@END_MSINTERNAL
) continue;
if (i == BUTTON_OK || bOkOnly) ph.SetElement(UIE_DEFBUTTON); else ph.SetElement(UIE_BUTTON);
int ay = m_rectBottomGradient.top; ph.Rectangle(b.rect.left, b.rect.top - ay, b.rect.right, b.rect.bottom - ay); RECT trect = b.textrect; OffsetRect(&trect, 0, -ay); DrawText(hDC, b.tszCaption, -1, &trect, DT_NOCLIP | DT_NOPREFIX); } }
pbm->Draw(hODC, m_rectBottomGradient.left, m_rectBottomGradient.top, bottomsize);
pbm->EndPaintInto(hBDC); delete pbm;
hDC = hODC;
{ CPaintHelper ph(m_uig, hDC);
ph.SetElement(UIE_BORDER);
ph.MoveTo(0, m_rectTopGradient.bottom); ph.LineTo(0, m_rectBottomGradient.top);
ph.MoveTo(WINDOW_WIDTH - 1, m_rectTopGradient.bottom); ph.LineTo(WINDOW_WIDTH - 1, m_rectBottomGradient.top); } }
void CConfigWnd::OnClick(POINT point, WPARAM fwKeys, BOOL bLeft) { int i;
// Un-highlight the current callout
SendMessage(CFlexWnd::s_CurrPageHwnd, WM_UNHIGHLIGHT, 0, 0);
// check scroll tab buttons
if (m_bScrollTabs) for (i = 0; i < 2; i++) { RECT &r = !i ? m_rectSTRight : m_rectSTLeft; BOOL b = !i ? m_bScrollTabsRight : m_bScrollTabsLeft; if (PtInRect(&r, point)) { if (b) ScrollTabs(!i ? -1 : 1); return; } }
// check tabs
for (i = 0; i < GetNumElements(); i++) if (PtInRect(&(GetElement(i).rect), point)) { // Check if the tab is partially obscured. If so we scroll the tab so it becomes completely visible.
POINT pt = {m_rectSTLeft.left, m_rectSTLeft.top}; if (m_bScrollTabsRight || m_bScrollTabsLeft) { while (PtInRect(&(GetElement(i).rect), pt)) ScrollTabs(1); } SelTab(i); return; }
// check buttons
for (i = 0; i < NUMBUTTONS; i++) if (PtInRect(&(m_Button[i].rect), point)) { FireButton(i); return; } }
void CConfigWnd::ScrollTabs(int by) { m_nLeftTab += by; if (m_nLeftTab < 0) m_nLeftTab = 0; if (m_nLeftTab >= GetNumElements()) m_nLeftTab = GetNumElements() - 1; CalcTabs(); Invalidate(); }
void CConfigWnd::OnDestroy() { tracescope(__ts, _T("CConfigWnd::OnDestroy()\n")); ClipCursor(NULL); // Set cursor extent to entire desktop.
if (m_bCreated) PostQuitMessage(EXIT_SUCCESS); }
LRESULT CConfigWnd::OnCreate(LPCREATESTRUCT lpCreateStruct) { tracescope(__ts, _T("CConfigWnd::OnCreate()\n"));
if (!Init()) { etrace(_T("CConfigWnd::Init() failed\n")); return -1; } else m_bCreated = TRUE;
return 0; }
BOOL CALLBACK EnumDeviceCallback(const DIDEVICEINSTANCEW *lpdidi, LPDIRECTINPUTDEVICE8W pdiDev8W, DWORD dwFlags, DWORD dwDeviceRemaining, LPVOID pvRef) { if (pvRef != NULL) return ((CConfigWnd *)pvRef)->EnumDeviceCallback(lpdidi); else return DIENUM_STOP; }
BOOL CConfigWnd::EnumDeviceCallback(const DIDEVICEINSTANCEW *lpdidi) { DIDEVICEINSTANCEW didi; didi.dwSize = sizeof(DIDEVICEINSTANCEW); didi.guidInstance = lpdidi->guidInstance; didi.guidProduct = lpdidi->guidProduct; didi.dwDevType = lpdidi->dwDevType; CopyStr(didi.tszInstanceName, lpdidi->tszInstanceName, MAX_PATH); CopyStr(didi.tszProductName, lpdidi->tszProductName, MAX_PATH); didi.guidFFDriver = lpdidi->guidFFDriver; didi.wUsagePage = lpdidi->wUsagePage; didi.wUsage = lpdidi->wUsage;
AddToList(&didi);
return DIENUM_CONTINUE; }
// show any error message here if returning false
BOOL CConfigWnd::Init(DWORD dwInitFlags) { tracescope(__ts, _T("CConfigWnd::Init()\n"));
HRESULT hr = S_OK; BOOL bReInit = !!(dwInitFlags & CFGWND_INIT_REINIT);
m_dwInitFlags = dwInitFlags; SetOnFunctionExit<DWORD> _set_m_dwInitFlags(m_dwInitFlags, 0);
// make sure we have DI
assert(m_lpDI != NULL); if (m_lpDI == NULL) { etrace(_T("NULL m_lpDI\n")); return FALSE; }
if (!(dwInitFlags & CFGWND_INIT_RESET)) { // If we are not doing reset, clear device list then re-enumerate and rebuild.
// clear list
ClearList();
// enum devices
{ tracescope(ts, _T("Enumerating Devices...\n\n"));
DWORD dwFlags = DIEDBSFL_ATTACHEDONLY; hr = m_lpDI->EnumDevicesBySemantics(NULL, (LPDIACTIONFORMATW)&m_uig.RefMasterAcFor(m_nCurGenre), ::EnumDeviceCallback, (LPVOID)this, dwFlags);
trace(_T("\n")); } } else { DIDEVICEINSTANCEW didiCopy; // Saves a copy of device instance as the current ELEMENT will be freed by AddToList().
CopyMemory(&didiCopy, &GetElement(m_CurSel).didi, sizeof(didiCopy)); // If resetting, call AddToList with bReset as TRUE to just get default mappings.
AddToList(&didiCopy, TRUE); }
// handle potential enum failure
if (FAILED(hr)) { etrace1(_T("EnumDevicesBySemantics() failed, returning 0x%08x\n"), hr); return FALSE; }
// if there are no elements, fail
if (GetNumElements() < 1) { etrace(_T("No devices\n")); return FALSE; }
// calculate tabs, buttons, init gradients
CalcTabs(); if (!bReInit) { CalcButtons(); InitGradients();
// set the timer
if (InRenderMode()) { if (g_fptimeSetEvent) g_fptimeSetEvent(20, 20, CConfigWnd::TimerProc, (DWORD_PTR)m_hWnd, TIME_ONESHOT); Render(); } }
// make sure all the pages are in the right place
PlacePages();
// show the first page if we are not resetting. Show current page if we are.
int CurSel = (dwInitFlags & CFGWND_INIT_RESET) ? m_CurSel : 0; m_CurSel = -1; SelTab(CurSel);
// if we're already editting the layout, set it.
// KLUDGE, set false and toggle to set
if (m_bEditLayout) { m_bEditLayout = FALSE; ToggleLayoutEditting(); }
trace(_T("\n"));
return TRUE; }
// This is called once for each device that will get configured.
int CConfigWnd::AddToList(const DIDEVICEINSTANCEW *lpdidi, BOOL bReset) { if (lpdidi == NULL) { etrace(_T("NULL lpdidi")); assert(0); return GetNumElements(); }
int i;
tracescope(ts, _T("Adding Device ")); trace(QSAFESTR(lpdidi->tszInstanceName)); trace(_T("\n\n"));
// add an element and get it if we are not doing reset (adding new device)
if (!bReset) { i = GetNumElements(); m_Element.SetSize(i + 1); } else { i = m_CurSel; ClearElement(m_CurSel, bReset); // If resetting, clear the current ELEMENT as we will populate it below.
}
// If we are doing reset, then we use the existing ELEMENT that this device is already using.
ELEMENT &e = bReset ? GetElement(m_CurSel) : GetElement(i);
// set various needed variables
e.didi = *lpdidi; e.bCalc = FALSE; e.pUIGlobals = &m_uig;
// create and set the device
if (m_lpDI == NULL) { e.lpDID = NULL; etrace(_T("m_lpDI NULL! Can't create this device.\n")); } else { e.lpDID = CreateDevice(e.didi.guidInstance); if (!e.lpDID) etrace(_T("Failed to create device!\n")); }
if (!bReset) { // Find owner of device only if we are not doing reset.
// set starting current user index
DIPROPSTRING dips; dips.diph.dwSize = sizeof(DIPROPSTRING); dips.diph.dwHeaderSize = sizeof(DIPROPHEADER); dips.diph.dwObj = DIPH_DEVICE; dips.diph.dwHow = 0; CopyStr(dips.wsz, "", MAX_PATH); if (!e.lpDID) { etrace(_T("no lpDID, assuming device unassigned\n")); e.nCurUser = -1; } //@@BEGIN_MSINTERNAL
#ifdef DDKBUILD
else if (m_uig.QueryAllowEditLayout()) { trace(_T("In DDK mode. Set user to 0 automatically.\n")); e.nCurUser = 0; } #endif
//@@END_MSINTERNAL
else { HRESULT hr = e.lpDID->GetProperty(DIPROP_USERNAME, (LPDIPROPHEADER)&dips); e.nCurUser = -1; // unassigned unless getusernameindex below works
if (FAILED(hr)) etrace(_T("GetProperty(DIPROP_USERNAME,...) failed\n")); else if (hr == S_FALSE) trace(_T("GetProperty(DIPROP_USERNAME,...) returned S_FALSE\n")); else if (StrLen(dips.wsz) < 1) trace(_T("GetProperty(DIPROP_USERNAME,...) returned empty string\n")); else { trace(_T("Getting user name index for ")); traceWSTR(dips.wsz); e.nCurUser = m_uig.GetUserNameIndex(dips.wsz); trace(_T("Result: ")); traceLONG(e.nCurUser); if (e.nCurUser == -1) etrace(_T("Device assigned to user not passed to ConfigureDevices()\nConsidering unassigned now\n")); } } }
// create and set the page object
HWND hwndChild = NULL; e.pPage = CreatePageObject(i, e, hwndChild); if (e.pPage == NULL) etrace(_T("Failed to create page object!\n")); e.hWnd = hwndChild; if (e.hWnd == NULL) etrace(_T("CreatePageObject() returned NULL hwnd!\n"));
// create/test the first acfor for this device with cur genre/user
traceLONG(m_nCurGenre); traceLONG(e.nCurUser); LPDIACTIONFORMATW lpAcFor = NULL; if (e.nCurUser != -1) { lpAcFor = e.GetAcFor(m_nCurGenre, e.nCurUser, bReset); if (lpAcFor != NULL) TraceActionFormat(_T("Starting Device ActionFormat:"), *lpAcFor); else etrace(_T("Failed to create starting ActionFormat\n")); } else trace(_T("Device unassigned\n"));
// check if anything was unsuccessful
if ((lpAcFor == NULL && e.nCurUser != -1) || e.lpDID == NULL || e.pPage == NULL || e.hWnd == NULL) { // clear what was successful, set the size back (remove element),
// and indicate error
ClearElement(e); m_Element.SetSize(i); etrace(_T("Can't add this device - Element removed\n")); }
trace(_T("\n"));
return GetNumElements(); }
LPDIRECTINPUTDEVICE8W CConfigWnd::CreateDevice(GUID &guid) { LPDIRECTINPUTDEVICE8W lpDID;
HRESULT hr = m_lpDI->CreateDevice(guid, &lpDID, NULL); if (FAILED(hr) || lpDID == NULL) { etrace2(_T("Could not create device (guid %s), CreateDevice() returned 0x%08x\n"), GUIDSTR(guid), hr); return NULL; } return lpDID; }
void CConfigWnd::ClearElement(int i, BOOL bReset) { ELEMENT &e = GetElement(i); ClearElement(e, bReset); }
void CConfigWnd::ClearElement(ELEMENT &e, BOOL bReset) { if (e.pPage != NULL) DestroyPageObject(e.pPage); if (e.lpDID != NULL) { e.lpDID->Release(); e.lpDID = NULL; } e.pPage = NULL; e.lpDID = NULL; e.hWnd = NULL; e.pUIGlobals = NULL; // not freed
if (!bReset) // Free map only if we are not resetting (delete permanently).
e.FreeMap(); }
void CConfigWnd::ClearList() { int i; for (i = 0; i < GetNumElements(); i++) ClearElement(i); m_Element.RemoveAll(); assert(!GetNumElements()); }
void CConfigWnd::PlacePages() { RECT rect; GetPageRect(rect);
for (int i = 0; i < GetNumElements(); i++) { DWORD flags = SWP_NOZORDER | SWP_NOACTIVATE; SetWindowPos(GetElement(i).hWnd, NULL, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, flags); } }
SIZE CConfigWnd::GetTextSize(LPCTSTR tszText) { RECT trect = {0, 0, 1, 1}; HDC hDC = CreateCompatibleDC(NULL); if (hDC != NULL) { { CPaintHelper ph(m_uig, hDC); ph.SetFont(UIF_FRAME); DrawText(hDC, tszText, -1, &trect, DT_CALCRECT | DT_NOPREFIX); } DeleteDC(hDC); } SIZE size = {trect.right - trect.left, trect.bottom - trect.top}; return size; }
void CConfigWnd::InitGradients() { if (m_pbmTopGradient == NULL) m_pbmTopGradient = CBitmap::CreateHorzGradient(m_rectTopGradient, m_uig.GetColor(UIC_CONTROLFILL), m_uig.GetColor(UIC_CONTROLFILL)); if (m_pbmBottomGradient == NULL) m_pbmBottomGradient = CBitmap::CreateHorzGradient(m_rectBottomGradient, m_uig.GetColor(UIC_CONTROLFILL), m_uig.GetColor(UIC_CONTROLFILL)); }
void CConfigWnd::CalcTabs() { int i, maxh = 0, lastx = 0; for (i = 0; i < GetNumElements(); i++) { ELEMENT &e = GetElement(i); CopyStr(e.tszCaption, e.didi.tszInstanceName, MAX_PATH); e.rect.left = i > 0 ? GetElement(i - 1).rect.right - 1 : 0; e.rect.top = 0; SIZE tsize = GetTextSize(e.tszCaption); e.textrect.left = e.textrect.top = 0; e.textrect.right = tsize.cx; e.textrect.bottom = tsize.cy; OffsetRect(&e.textrect, e.rect.left + TABTEXTMARGINLEFT, e.rect.top + TABTEXTMARGINTOP); int w = tsize.cx; int h = tsize.cy; e.rect.right = e.rect.left + TABTEXTMARGINLEFT + w + TABTEXTMARGINRIGHT + 1; e.rect.bottom = e.rect.top + TABTEXTMARGINTOP + h + TABTEXTMARGINBOTTOM; h = e.rect.bottom - e.rect.top; if (h > maxh) maxh = h; e.bCalc = TRUE; }
for (i = 0; i < GetNumElements(); i++) { ELEMENT &e = GetElement(i); e.rect.bottom = e.rect.top + maxh; lastx = e.rect.right; }
if (lastx > WINDOW_WIDTH) { if (!m_bScrollTabs) m_nLeftTab = 0; m_bScrollTabs = TRUE; } else { m_bScrollTabs = FALSE; m_nLeftTab = 0; }
int cutoff = WINDOW_WIDTH; if (m_bScrollTabs) { cutoff = WINDOW_WIDTH - maxh * 2; RECT r = {WINDOW_WIDTH - maxh, 0, WINDOW_WIDTH, maxh}; m_rectSTLeft = r; OffsetRect(&r, -(maxh - 1), 0); m_rectSTRight = r; }
if (m_bScrollTabs && m_nLeftTab > 0) { int left = GetElement(m_nLeftTab).rect.left, right = 0; for (i = 0; i < GetNumElements(); i++) { ELEMENT &e = GetElement(i); OffsetRect(&e.rect, -left, 0); OffsetRect(&e.textrect, -left, 0); if (e.rect.right > right) right = e.rect.right; } lastx = right; }
if (m_bScrollTabs) { m_bScrollTabsLeft = lastx > cutoff && m_nLeftTab < GetNumElements() - 1; m_bScrollTabsRight = m_nLeftTab > 0; }
RECT t = {0/*lastx*/, 0, WINDOW_WIDTH, maxh}; m_rectTopGradient = t; }
void CConfigWnd::CalcButtons() { SIZE max = {0, 0}; int i; for (i = 0; i < NUMBUTTONS; i++) { BUTTON &b = m_Button[i];
if (!StrLen(b.tszCaption)) { switch (i) { case BUTTON_RESET: LoadString(g_hModule, IDS_BUTTON_RESET, b.tszCaption, MAX_PATH); break;
//@@BEGIN_MSINTERNAL
#ifdef DDKBUILD
case BUTTON_LAYOUT: LoadString(g_hModule, IDS_BUTTON_LAYOUT, b.tszCaption, MAX_PATH); break; #endif
//@@END_MSINTERNAL
case BUTTON_CANCEL: if (m_uig.InEditMode()) { LoadString(g_hModule, IDS_BUTTON_CANCEL, b.tszCaption, MAX_PATH); break; } // else, intentional fallthrough
case BUTTON_OK: LoadString(g_hModule, IDS_BUTTON_OK, b.tszCaption, MAX_PATH); break; } }
b.textsize = GetTextSize(b.tszCaption);
if (b.textsize.cx > max.cx) max.cx = b.textsize.cx; if (b.textsize.cy > max.cy) max.cy = b.textsize.cy; }
max.cx += BUTTONTEXTMARGINLEFT + BUTTONTEXTMARGINRIGHT; max.cy += BUTTONTEXTMARGINTOP + BUTTONTEXTMARGINBOTTOM;
m_rectBottomGradient.bottom = WINDOW_HEIGHT; m_rectBottomGradient.top = m_rectBottomGradient.bottom - max.cy - BARBUTTONMARGINTOP - BARBUTTONMARGINBOTTOM; m_rectBottomGradient.left = 0; m_rectBottomGradient.right = WINDOW_WIDTH;
for (i = 0; i < NUMBUTTONS; i++) { BUTTON &b = m_Button[i];
RECT z = {0,0,0,0};
b.rect = z; b.rect.right = max.cx; b.rect.bottom = max.cy;
int by = m_rectBottomGradient.top + BARBUTTONMARGINTOP;
switch (i) { case BUTTON_RESET: OffsetRect(&b.rect, BARBUTTONMARGINLEFT, by); break;
//@@BEGIN_MSINTERNAL
#ifdef DDKBUILD
case BUTTON_LAYOUT: OffsetRect(&b.rect, WINDOW_WIDTH / 2 - max.cx / 2, by); break; #endif
//@@END_MSINTERNAL
case BUTTON_CANCEL: OffsetRect(&b.rect, m_rectBottomGradient.right - BARBUTTONMARGINRIGHT - max.cx, by); break;
case BUTTON_OK: OffsetRect(&b.rect, m_rectBottomGradient.right - BARBUTTONMARGINRIGHT - max.cx - max.cx - BARBUTTONSPACING, by); break; }
POINT m = {(b.rect.right + b.rect.left) / 2, (b.rect.bottom + b.rect.top) / 2}; b.textrect.left = m.x - b.textsize.cx / 2; b.textrect.top = m.y - b.textsize.cy / 2; b.textrect.right = b.textrect.left + b.textsize.cx; b.textrect.bottom = b.textrect.top + b.textsize.cy; } }
void CConfigWnd::GetPageRect(RECT &rect, BOOL bTemp) { if (bTemp) { rect.left = 1; rect.right = WINDOW_WIDTH - 1; rect.top = 40; rect.bottom = WINDOW_HEIGHT - 40; } else { rect.left = 1; rect.right = WINDOW_WIDTH - 1; rect.top = m_rectTopGradient.bottom; rect.bottom = m_rectBottomGradient.top; } }
void CConfigWnd::ToggleLayoutEditting() { m_bEditLayout = !m_bEditLayout;
for (int i = 0; i < GetNumElements(); i++) { ELEMENT &e = GetElement(i); if (e.pPage) e.pPage->SetEditLayout(m_bEditLayout); } }
void CConfigWnd::FireButton(int b) { switch(b) { case BUTTON_OK: if (!m_uig.InEditMode()) break; // If not in edit mode, Ok button doesn't not exist so we shouldn't do anything.
//@@BEGIN_MSINTERNAL
#ifdef DDKBUILD
if (m_uig.QueryAllowEditLayout()) { int MsgBoxRet = MessageBox(m_hWnd, _T("Do you wish to save layout information?"), _T("Save"), MB_YESNOCANCEL); if (MsgBoxRet == IDYES) { // Write IHV settings for all devices.
for (int i = 0; i < GetNumElements(); i++) GetElement(i).pPage->WriteIHVSetting(); } else if (MsgBoxRet == IDCANCEL) break; } else #endif
//@@END_MSINTERNAL
Apply(); // If we are in Edit Layout mode, do not call Apply() to save to user setting.
// intentional fallthrough
case BUTTON_CANCEL: Destroy(); break;
case BUTTON_RESET: if (m_uig.InEditMode()) // Only reset if in edit mode. Do nothing in view mode.
Reset(); break;
//@@BEGIN_MSINTERNAL
#ifdef DDKBUILD
case BUTTON_LAYOUT: if (m_uig.QueryAllowEditLayout()) ToggleLayoutEditting(); break; #endif
//@@END_MSINTERNAL
default: assert(0); break; } }
void CConfigWnd::SelTab(int i) { if (i >= 0 && i < GetNumElements()) { if (i == m_CurSel) return; ShowPage(i); HidePage(m_CurSel); m_CurSel = i; Invalidate(); } }
PAGETYPE *CConfigWnd::CreatePageObject(int nPage, const ELEMENT &e, HWND &refhChildWnd) { if (m_pPageFactory == NULL) return NULL;
PAGETYPE *pPage = NULL; HRESULT hresult = m_pPageFactory->CreateInstance(NULL, IID_IDIDeviceActionConfigPage, (LPVOID*) &pPage); if (FAILED(hresult) || pPage == NULL) return NULL;
DICFGPAGECREATESTRUCT cs; cs.dwSize = sizeof(DICFGPAGECREATESTRUCT); cs.nPage = nPage; cs.hParentWnd = m_hWnd; GetPageRect(cs.rect, TRUE); cs.hPageWnd = NULL; cs.didi = e.didi; cs.lpDID = e.lpDID; cs.pUIGlobals = &m_uig; cs.pUIFrame = dynamic_cast<IDIConfigUIFrameWindow *>(this);
hresult = pPage->Create(&cs); if (FAILED(hresult)) { etrace1(_T("pPage->Create() failed, returning 0x%08x\n"), hresult); pPage->Release(); return NULL; }
refhChildWnd = cs.hPageWnd;
return pPage; }
void CConfigWnd::DestroyPageObject(PAGETYPE *&pPage) { if (pPage != NULL) pPage->Release(); pPage = NULL; }
void CConfigWnd::ShowPage(int i) { if (i == -1) return;
if (i < 0 || i >= GetNumElements()) { assert(0); return; }
ELEMENT &e = GetElement(i);
PAGETYPE *pPage = e.pPage; if (pPage == NULL) { assert(0); return; }
pPage->Show(e.GetAcFor(m_nCurGenre, e.nCurUser)); }
void CConfigWnd::HidePage(int i) { if (i == -1) return;
if (i < 0 || i >= GetNumElements()) { assert(0); return; }
PAGETYPE *pPage = GetElement(i).pPage; if (pPage == NULL) { assert(0); return; }
pPage->Hide(); }
void CConfigWnd::OnMouseOver(POINT point, WPARAM fwKeys) { int i;
CFlexWnd::s_ToolTip.SetEnable(FALSE);
// check scroll tab buttons
if (m_bScrollTabs) for (i = 0; i < 2; i++) { RECT &r = !i ? m_rectSTRight : m_rectSTLeft; BOOL b = !i ? m_bScrollTabsRight : m_bScrollTabsLeft; if (PtInRect(&r, point)) { if (b) GetElement(m_CurSel).pPage->SetInfoText(m_uig.InEditMode() ? IDS_INFOMSG_EDIT_TABSCROLL : IDS_INFOMSG_VIEW_TABSCROLL); return; } }
// check tabs
for (i = 0; i < GetNumElements(); i++) if (PtInRect(&(GetElement(i).rect), point)) { GetElement(m_CurSel).pPage->SetInfoText(m_uig.InEditMode() ? IDS_INFOMSG_EDIT_TAB : IDS_INFOMSG_VIEW_TAB); return; }
// check buttons
for (i = 0; i < NUMBUTTONS; i++) if (PtInRect(&(m_Button[i].rect), point)) { switch(i) { case BUTTON_OK: if (m_uig.InEditMode()) GetElement(m_CurSel).pPage->SetInfoText(IDS_INFOMSG_EDIT_OK); break;
case BUTTON_CANCEL: if (m_uig.InEditMode()) GetElement(m_CurSel).pPage->SetInfoText(IDS_INFOMSG_EDIT_CANCEL); else GetElement(m_CurSel).pPage->SetInfoText(IDS_INFOMSG_VIEW_OK); break;
case BUTTON_RESET: if (m_uig.InEditMode()) // Only reset if in edit mode. Do nothing in view mode.
GetElement(m_CurSel).pPage->SetInfoText(IDS_INFOMSG_EDIT_RESET); break; } return; }
GetElement(m_CurSel).pPage->SetInfoText(-1); }
void CALLBACK CConfigWnd::TimerProc(UINT uID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2) { if (!IsWindow((HWND)dwUser)) return; // Verify that dwUser is a valid window handle
CConfigWnd *pCfgWnd = (CConfigWnd *)GetFlexWnd((HWND)dwUser); // Get flex object
// We use PostMessage instead of calling Render() so we stay synchronized.
PostMessage((HWND)dwUser, WM_DIRENDER, 0, 0); }
void CConfigWnd::MapBitmaps(HDC hDC) { if (m_bBitmapsMapped) return;
if (m_pbmTopGradient) m_pbmTopGradient->MapToDC(hDC); if (m_pbmBottomGradient) m_pbmBottomGradient->MapToDC(hDC);
m_bBitmapsMapped = TRUE; }
LPDIACTIONFORMATW CConfigWnd::GetCurAcFor(ELEMENT &e) { return e.GetAcFor(m_nCurGenre, e.nCurUser); }
BOOL CConfigWnd::IsActionAssignedAnywhere(GUID GuidInstance, int nActionIndex) { // Find out which user owns the device in question first.
int nUser = 0; for (int ii = 0; ii < GetNumElements(); ii++) { ELEMENT &e = GetElement(ii); if (IsEqualGUID(e.didi.guidInstance, GuidInstance)) { nUser = e.nCurUser; break; } }
// Now we check the actions against this user.
for (int i = 0; i < GetNumElements(); i++) { ELEMENT &e = GetElement(i); const LPDIACTIONFORMATW &lpAcFor = e.GetAcFor(m_nCurGenre, nUser);
if (lpAcFor == NULL) continue;
if (nActionIndex < 0 || nActionIndex > int(lpAcFor->dwNumActions)) continue;
// If this device is not owned by this user, don't need to check.
if (e.nCurUser != nUser) continue;
const DIACTIONW &a = lpAcFor->rgoAction[nActionIndex];
if (!IsEqualGUID(a.guidInstance, GUID_NULL)) return TRUE; }
return FALSE; }
LRESULT CConfigWnd::WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_ACTIVATE: switch(wParam) { case WA_ACTIVE: case WA_CLICKACTIVE: // Set the cursor extent to this window if we are in render mode because the
// cursor can't be drawn by us when it's not above us.
if (InRenderMode()) { RECT rc; GetWindowRect(m_hWnd, &rc); ClipCursor(&rc); } // Reacquire current device
if (GetNumElements() && m_CurSel >= 0) GetElement(m_CurSel).pPage->Reacquire(); break; case WA_INACTIVE: // Unacquire current device
if (GetNumElements() && m_CurSel >= 0) GetElement(m_CurSel).pPage->Unacquire(); break; } break;
case WM_DIRENDER: // Render message, sent by TimerProc() earlier.
// The timer proc has request a render operation.
Render(m_bNeedRedraw);
// Set the next timer event.
if (g_fptimeSetEvent) g_fptimeSetEvent(20, 20, CConfigWnd::TimerProc, (DWORD_PTR)m_hWnd, TIME_ONESHOT); return 0;
case WM_SETFOCUS: // Set the keyboard focus to the current page window.
ShowPage(m_CurSel); // Call Show() on current page so it can get keyboard focus.
return 0;
// WM_NCHITTEST handler is added to support moving window when in GDI mode.
case WM_NCHITTEST: { if (InRenderMode()) break;
BOOL bHitCaption = TRUE; POINT point = {(short)LOWORD(lParam), (short)HIWORD(lParam)}; int i;
ScreenToClient(m_hWnd, &point); // check scroll tab buttons
if (m_bScrollTabs) for (i = 0; i < 2; i++) { RECT &r = !i ? m_rectSTRight : m_rectSTLeft; BOOL b = !i ? m_bScrollTabsRight : m_bScrollTabsLeft; if (PtInRect(&r, point)) { if (b) bHitCaption = FALSE; break; } }
// check tabs
for (i = 0; i < GetNumElements(); i++) if (PtInRect(&(GetElement(i).rect), point)) { bHitCaption = FALSE; break; }
// check buttons
for (i = 0; i < NUMBUTTONS; i++) if (PtInRect(&(m_Button[i].rect), point)) { if ((i == BUTTON_RESET || i == BUTTON_OK) && !m_uig.InEditMode()) continue; //@@BEGIN_MSINTERNAL
#ifdef DDKBUILD
if (i == BUTTON_LAYOUT && !m_uig.QueryAllowEditLayout()) continue; #endif
//@@END_MSINTERNAL
bHitCaption = FALSE; break; }
// Check Y coordinate to see if it is within the caption bar.
if ((point.y < GetElement(0).rect.top || point.y > GetElement(0).rect.bottom) && (point.y < m_rectBottomGradient.top || point.y > m_rectBottomGradient.bottom)) bHitCaption = FALSE;
if (bHitCaption) { // If we are returning HTCAPTION, clear the page's info box.
GetElement(m_CurSel).pPage->SetInfoText(-1); return HTCAPTION; } break; }
case WM_CFGUIRESET: { CFlexWnd::s_ToolTip.SetEnable(FALSE); m_bHourGlass = TRUE; // Set the flag so Render() will draw hourglass instead of arrow
Invalidate(); SendMessage(this->m_hWnd, WM_PAINT, 0, 0); if (InRenderMode()) // If in render mode, need to specifically call OnRender as sending WM_PAINT merely changes flag.
Render(TRUE); if (!Init(CFGWND_INIT_REINIT | CFGWND_INIT_RESET)) { m_uig.SetFinalResult(E_FAIL); Destroy(); } m_bHourGlass = FALSE; // Change cursor back to arrow
m_MsgBox.Destroy(); Invalidate(); return TRUE; }
case WM_SETCURSOR: { static HCURSOR hCursor = LoadCursor(NULL, IDC_ARROW); ::SetCursor(InRenderMode() ? NULL : hCursor); } return TRUE;
// case WM_QUERYACTIONASSIGNEDANYWHERE:
// return IsActionAssignedAnywhere(int(wParam), int(lParam));
}
return CFlexWnd::WndProc(hWnd, msg, wParam, lParam); }
HRESULT CConfigWnd::Apply() { tracescope(ts, _T("\n\nApplying Changes to All Devices...\n"));
// Devices need to be in the unaquired state when SetActionMap is called.
Unacquire();
for (int i = 0; i < GetNumElements(); i++) GetElement(i).Apply();
Reacquire();
trace(_T("\n\n"));
return S_OK; }
int CConfigWnd::GetNumElements() { return m_Element.GetSize(); }
ELEMENT &CConfigWnd::GetElement(int i) { if (i < 0 || i >= GetNumElements()) { assert(0); etrace1(_T("Tried to get invalid element %d\n"), i); return m_InvalidElement; }
return m_Element[i]; }
// This function returns a pointer to the action format of the device that has the given GUID
HRESULT CConfigWnd::GetActionFormatFromInstanceGuid(LPDIACTIONFORMATW *lplpAcFor, REFGUID Guid) { if (!lplpAcFor) return E_INVALIDARG;
for (int i = 0; i < GetNumElements(); i++) { ELEMENT &e = m_Element[i];
if (e.didi.guidInstance == Guid) { *lplpAcFor = GetCurAcFor(e); return S_OK; } }
return E_INVALIDARG; }
HDC CConfigWnd::GetRenderDC() { assert(InRenderMode());
if (m_bRender3D) return m_pbm3D == NULL ? NULL : m_pbm3D->BeginPaintInto(); else { if (m_pSurface == NULL) return NULL;
HDC hDC = NULL; HRESULT hr = m_pSurface->GetDC(&hDC); if (FAILED(hr)) if (hr == DDERR_SURFACELOST) { m_pSurface->Restore(); // Restore the surface
hr = m_pSurface->GetDC(&hDC); // Retry
if (FAILED(hr)) return NULL; } else return NULL;
return hDC; } }
void CConfigWnd::ReleaseRenderDC(HDC &phDC) { assert(InRenderMode());
HDC hDC = phDC; phDC = NULL;
if (m_bRender3D) { if (m_pbm3D == NULL) return;
m_pbm3D->EndPaintInto(hDC); } else { if (m_pSurface == NULL) return;
m_pSurface->ReleaseDC(hDC); } }
struct BITMAPINFO_3MASKS { BITMAPINFOHEADER bmiHeader; RGBQUAD bmiColors[3]; };
void CConfigWnd::Create3DBitmap() { HDC hDC = CreateCompatibleDC(NULL);
BITMAPINFO_3MASKS bmi3mask; // BITMAPINFO with 3 DWORDs for bmiColors
BITMAPINFO *pbmi = (BITMAPINFO*)&bmi3mask;
BITMAPINFOHEADER &h = pbmi->bmiHeader; h.biSize = sizeof(BITMAPINFOHEADER); h.biWidth = WINDOW_WIDTH; h.biHeight = -WINDOW_HEIGHT; h.biPlanes = 1; h.biSizeImage = 0; h.biXPelsPerMeter = 100; h.biYPelsPerMeter = 100; h.biClrImportant = 0;
// Get the surface's pixel format
D3DSURFACE_DESC d3dsd; ZeroMemory(&d3dsd, sizeof(d3dsd)); m_pSurface3D->GetDesc(&d3dsd); m_SurfFormat = d3dsd.Format; switch(d3dsd.Format) { case D3DFMT_R5G6B5: h.biClrUsed = 3; h.biBitCount = 16; m_uiPixelSize = 2; h.biCompression = BI_BITFIELDS; *((LPDWORD)pbmi->bmiColors) = 0xF800; *((LPDWORD)pbmi->bmiColors+1) = 0x07E0; *((LPDWORD)pbmi->bmiColors+2) = 0x001F; break;
case D3DFMT_X1R5G5B5: case D3DFMT_A1R5G5B5: h.biClrUsed = 3; h.biBitCount = 16; m_uiPixelSize = 2; h.biCompression = BI_BITFIELDS; *((LPDWORD)pbmi->bmiColors) = 0x7C00; *((LPDWORD)pbmi->bmiColors+1) = 0x03E0; *((LPDWORD)pbmi->bmiColors+2) = 0x001F; break;
case D3DFMT_R8G8B8: h.biClrUsed = 0; h.biBitCount = 24; m_uiPixelSize = 3; h.biCompression = BI_RGB; break;
case D3DFMT_A8R8G8B8: case D3DFMT_X8R8G8B8: default: // Use 32 bits for all other formats
h.biClrUsed = 0; h.biBitCount = 32; m_uiPixelSize = 4; h.biCompression = BI_RGB; break; }
HBITMAP hbm = CreateDIBSection( hDC, pbmi, DIB_RGB_COLORS, &m_p3DBits, NULL, 0);
DeleteDC(hDC); hDC = NULL;
if (hbm != NULL) m_pbm3D = CBitmap::StealToCreate(hbm);
if (hbm != NULL) DeleteObject((HGDIOBJ)hbm); hbm = NULL; }
void CConfigWnd::Copy3DBitmapToSurface3D() { assert(m_bRender3D);
if (m_p3DBits == NULL || m_pbm3D == NULL || m_pSurface3D == NULL) { etrace(_T("One or more of the vars required for Copy3DBitmapToSurface() was NULL!\n")); return; }
RECT rect = {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT};
HRESULT hr = D3DXLoadSurfaceFromMemory( m_pSurface3D, NULL, NULL,//&rect,
m_p3DBits, m_SurfFormat, WINDOW_WIDTH * m_uiPixelSize, NULL, &rect, D3DX_FILTER_POINT, 0); // Disable Color Key
}
void CConfigWnd::CallRenderCallback() { LPDICONFIGUREDEVICESCALLBACK pCallback = m_uig.GetCallback(); LPVOID pvRefData = m_uig.GetRefData();
if (pCallback == NULL) return;
if (m_bRender3D) { Copy3DBitmapToSurface3D(); pCallback(m_pSurface3D, pvRefData); } else { pCallback(m_pSurface, pvRefData); } }
void CConfigWnd::OnRender(BOOL bInternalCall) { m_bNeedRedraw = TRUE; }
void CConfigWnd::Render(BOOL bInternalCall) { tracescope(__ts, _T("CConfigWnd::Render() ")); traceBOOL(bInternalCall);
m_bNeedRedraw = FALSE;
ValidateRect(m_hWnd, NULL);
if (m_hWnd == NULL) return;
HDC hDC = GetRenderDC(); if (hDC == NULL) return;
if (bInternalCall) RenderInto(hDC);
static ICONINFO IconInfo; static HCURSOR hOldCursor = NULL; static HCURSOR hCursor; if (m_bHourGlass) hCursor = LoadCursor(NULL, IDC_WAIT); else hCursor = LoadCursor(NULL, IDC_ARROW); if (hCursor == NULL) return;
if (hOldCursor != hCursor) { hOldCursor = hCursor; GetIconInfo(hCursor, &IconInfo);
if (IconInfo.hbmMask) DeleteObject(IconInfo.hbmMask);
if (IconInfo.hbmColor) DeleteObject(IconInfo.hbmColor); }
POINT pt; GetCursorPos(&pt);
ScreenToClient(m_hWnd, &pt);
pt.x -= IconInfo.xHotspot; pt.y -= IconInfo.yHotspot;
if (m_pbmPointerEraser) m_pbmPointerEraser->Get(hDC, pt);
// If m_bHourGlass is true, we are resetting, so we don't draw mouse cursor.
if (hCursor && !m_bHourGlass) DrawIcon(hDC, pt.x, pt.y, hCursor);
ReleaseRenderDC(hDC);
CallRenderCallback();
hDC = GetRenderDC(); if (hDC == NULL) return;
if (m_pbmPointerEraser) m_pbmPointerEraser->Draw(hDC, pt);
ReleaseRenderDC(hDC); }
void CConfigWnd::Unacquire() { for (int i = 0; i < GetNumElements(); i++) { ELEMENT &e = m_Element[i]; if (e.pPage != NULL) e.pPage->Unacquire(); } }
void CConfigWnd::Reacquire() { for (int i = 0; i < GetNumElements(); i++) { ELEMENT &e = m_Element[i]; if (e.pPage != NULL) e.pPage->Reacquire(); } }
HRESULT CConfigWnd::Reset() { RECT rect; int iCenterX, iCenterY;
GetClientRect(&rect); iCenterX = (rect.left + rect.right) >> 1; iCenterY = (rect.top + rect.bottom) >> 1; rect.left = rect.right = iCenterX; rect.top = rect.bottom = iCenterY; InflateRect(&rect, g_iResetMsgBoxWidth >> 1, g_iResetMsgBoxHeight >> 1);
m_MsgBox.Create(m_hWnd, rect, FALSE); m_MsgBox.SetNotify(m_hWnd); m_MsgBox.SetFont((HFONT)m_uig.GetFont(UIE_USERNAMES)); m_MsgBox.SetColors(m_uig.GetTextColor(UIE_USERNAMES), m_uig.GetBkColor(UIE_USERNAMES), m_uig.GetTextColor(UIE_USERNAMESEL), m_uig.GetBkColor(UIE_USERNAMESEL), m_uig.GetBrushColor(UIE_USERNAMES), m_uig.GetPenColor(UIE_USERNAMES));
TCHAR tszResourceString[MAX_PATH]; LoadString(g_hModule, IDS_RESETMSG, tszResourceString, MAX_PATH); m_MsgBox.SetText(tszResourceString); ::ShowWindow(m_MsgBox.m_hWnd, SW_SHOW); ::SetWindowPos(m_MsgBox.m_hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_SHOWWINDOW); m_MsgBox.Invalidate(); return S_OK; }
HRESULT CConfigWnd::QueryActionAssignedAnywhere(GUID GuidInstance, int i) { return IsActionAssignedAnywhere(GuidInstance, i) ? S_OK : S_FALSE; }
int CConfigWnd::GetNumGenres() { return m_uig.GetNumMasterAcFors(); }
HRESULT CConfigWnd::SetCurUser(int nPage, int nUser) { // make sure we're using a valid element index
if (nPage < 0 || nPage >= GetNumElements()) { assert(0); return E_FAIL; }
// get the element
ELEMENT &e = GetElement(nPage); // don't do anything if we're already set to this user
if (e.nCurUser == nUser) return S_OK;
// store new curuser
e.nCurUser = nUser;
// if this page isn't the one currently shown, do nothing
// (it'll get the new acfor when it's shown)
if (m_CurSel != nPage) return S_OK;
// otherwised, cycle the page to reflect change
if (e.pPage) e.pPage->Unacquire(); HidePage(nPage); ShowPage(nPage); if (e.pPage) e.pPage->Reacquire();
return S_OK; }
HRESULT CConfigWnd::SetCurGenre(int NewGenre) { // if no change, do nothing
if (NewGenre == m_nCurGenre) return S_OK;
// make sure genre index is in range
if (NewGenre < 0 || NewGenre >= GetNumGenres()) return E_INVALIDARG;
// set genre
m_nCurGenre = NewGenre;
// store which page is currently up
int iOldPage = m_CurSel;
// for each page...
BOOL bShown = FALSE; for (int i = 0; i < GetNumElements(); i++) { ELEMENT &e = GetElement(i);
// hide the page and unacquire its device
if (e.pPage) { e.pPage->Unacquire(); HidePage(i); }
// show page if it was the old cur page
if (i == iOldPage && e.pPage && GetCurAcFor(e)) { ShowPage(i); bShown = TRUE; }
// reacquire device
if (e.pPage) e.pPage->Reacquire(); }
// if nothing was shown, show something
if (!bShown && GetNumElements() > 0) { m_CurSel = -1; SelTab(0); }
// if we showed the one we expected to show, we succeeded
return bShown ? S_OK : E_FAIL; }
int CConfigWnd::GetCurGenre() { return m_nCurGenre; }
HWND CConfigWnd::GetMainHWND() { return m_hWnd; }
// This is called by CDIDeviceActionConfigPage::DeviceUINotify.
// We scan the ELEMENT array and when we find a match, destroy and recreate the device
// object, then return it back to CDIDeviceActionConfigPage so it can update its pointer.
LPDIRECTINPUTDEVICE8W CConfigWnd::RenewDevice(GUID &GuidInstance) { for (int i = 0; i < GetNumElements(); i++) { ELEMENT &e = GetElement(i);
if (e.didi.guidInstance == GuidInstance) { // Releaes the instance we have
if (e.lpDID) { e.lpDID->Release(); e.lpDID = NULL; } // Recreate the device
e.lpDID = CreateDevice(e.didi.guidInstance); return e.lpDID; } } return NULL; }
LPDIACTIONFORMATW ELEMENT::GetAcFor(int nGenre, int nUser, BOOL bHwDefault) { // return null if requesting for unassigned user
if (nUser == -1) return NULL;
// validate params
if (!lpDID || !pUIGlobals || nGenre < 0 || nGenre >= pUIGlobals->GetNumMasterAcFors() || nUser < 0 || nUser >= pUIGlobals->GetNumUserNames()) { etrace(_T("ELEMENT::GetAcFor(): Invalid params\n")); return NULL; }
// generate dword id for map entry
DWORD dwMap = GENREUSER2MAP(nGenre, nUser);
// try to get that acfor
LPDIACTIONFORMATW lpAcFor = NULL; BOOL bFound = AcForMap.Lookup(dwMap, lpAcFor);
// if we found it and its not null and we are asked for hardware default setting, return it
if (bFound && lpAcFor && !bHwDefault) return lpAcFor;
// otherwise... we gotta make it
tracescope(__ts, _T("ELEMENT::GetAcFor")); trace2(_T("(%d, %d)\n"), nGenre, nUser); trace1(_T("Building map entry 0x%08x...\n"), dwMap);
// copy it from the masteracfor for the genre
lpAcFor = DupActionFormat(&(pUIGlobals->RefMasterAcFor(nGenre))); if (!lpAcFor) { etrace(_T("DupActionFormat() failed\n")); return NULL; }
// build it for the user
DWORD dwFlags = 0; if (bHwDefault //@@BEGIN_MSINTERNAL
#ifdef DDKBUILD
|| pUIGlobals->QueryAllowEditLayout() #endif
//@@END_MSINTERNAL
) dwFlags |= DIDBAM_HWDEFAULTS; LPCWSTR wszUserName = pUIGlobals->GetUserName(nUser); HRESULT hr = lpDID->BuildActionMap(lpAcFor, wszUserName, dwFlags); if (FAILED(hr)) { etrace4(_T("BuildActionMap(0x%p, %s, 0x%08x) failed, returning 0x%08x\n"), lpAcFor, QSAFESTR(wszUserName), dwFlags, hr); FreeActionFormatDup(lpAcFor); lpAcFor = NULL; return NULL; } else { trace3(_T("BuildActionMap(0x%p, %s, 0x%08x) succeeded\n"), lpAcFor, QSAFESTR(wszUserName), dwFlags); // Now we check if the return code is DI_WRITEPROTECT. If so, device can't be remapped.
if (hr == DI_WRITEPROTECT) { // The way we disable mapping is to add DIA_APPFIXED flag to all actions.
for (DWORD i = 0; i < lpAcFor->dwNumActions; ++i) lpAcFor->rgoAction[i].dwFlags |= DIA_APPFIXED; } }
// Here we copy the DIA_APPFIXED flag back to our action format for all DIACTION that had this.
const DIACTIONFORMATW &MasterAcFor = pUIGlobals->RefMasterAcFor(nGenre); for (DWORD i = 0; i < MasterAcFor.dwNumActions; ++i) if (MasterAcFor.rgoAction[i].dwFlags & DIA_APPFIXED) lpAcFor->rgoAction[i].dwFlags |= DIA_APPFIXED; // set it in the map
assert(lpAcFor != NULL); AcForMap.SetAt(dwMap, lpAcFor);
// return it
return lpAcFor; }
void ELEMENT::FreeMap() { POSITION pos = AcForMap.GetStartPosition(); while (pos != NULL) { DWORD dwMap = (DWORD)-1; LPDIACTIONFORMATW lpAcFor = NULL; AcForMap.GetNextAssoc(pos, dwMap, lpAcFor);
if (lpAcFor) FreeActionFormatDup(lpAcFor); } AcForMap.RemoveAll(); }
void ELEMENT::Apply() { tracescope(tsa, _T("\nELEMENT::Apply()\n")); trace1(_T("Applying Changes to Device %s\n"), QSAFESTR(didi.tszInstanceName));
if (lpDID == NULL) { etrace(_T("NULL lpDID, can't apply\n")); return; }
if (pUIGlobals == NULL) { etrace(_T("NULL pUIGlobals, can't apply\n")); return; }
LPDIACTIONFORMATW lpAcFor = NULL;
// go through the map and add the map keys to last if the user
// is the current user assignment, or to first if not
CList<DWORD, DWORD &> first, last; POSITION pos = AcForMap.GetStartPosition(); while (pos != NULL) { DWORD dwMap = (DWORD)-1; lpAcFor = NULL; AcForMap.GetNextAssoc(pos, dwMap, lpAcFor); if (MAP2USER(dwMap) == nCurUser) last.AddTail(dwMap); else first.AddTail(dwMap); }
// concatenate lists
first.AddTail(&last);
// now go through the resulting list (so that the current
// assignments are set last) if this device is assigned.
if (nCurUser != -1) { pos = first.GetHeadPosition(); while (pos != NULL) { DWORD dwMap = first.GetNext(pos); lpAcFor = AcForMap[dwMap];
tracescope(tsa2, _T("Applying lpAcFor at AcForMap[")); trace1(_T("0x%08x]...\n"), dwMap);
if (lpAcFor == NULL) { etrace(_T("NULL lpAcFor, can't apply\n")); continue; }
int nGenre = MAP2GENRE(dwMap); int nUser = MAP2USER(dwMap); LPCWSTR wszUserName = pUIGlobals->GetUserName(nUser);
traceLONG(nGenre); traceLONG(nUser); traceWSTR(wszUserName);
TraceActionFormat(_T("Final Device ActionFormat:"), *lpAcFor);
for (DWORD j = 0; j < lpAcFor->dwNumActions; ++j) { if( lpAcFor->rgoAction[j].dwObjID == (DWORD)-1 || IsEqualGUID(lpAcFor->rgoAction[j].guidInstance, GUID_NULL)) { lpAcFor->rgoAction[j].dwHow = DIAH_UNMAPPED; } else if( lpAcFor->rgoAction[j].dwHow & ( DIAH_USERCONFIG | DIAH_APPREQUESTED | DIAH_HWAPP | DIAH_HWDEFAULT | DIAH_DEFAULT ) ) { //@@BEGIN_MSINTERNAL
// ISSUE-2001/03/27-MarcAnd should look at doing this less destructively
// that is if everything is defaults then leave them alon
//@@END_MSINTERNAL
lpAcFor->rgoAction[j].dwHow = DIAH_USERCONFIG; } else if(IsEqualGUID(didi.guidInstance,lpAcFor->rgoAction[j].guidInstance)) { lpAcFor->rgoAction[j].dwHow = DIAH_USERCONFIG; } }
HRESULT hr; hr = lpDID->SetActionMap(lpAcFor, wszUserName, DIDSAM_FORCESAVE|DIDSAM_DEFAULT);
if (FAILED(hr)) etrace1(_T("SetActionMap() failed, returning 0x%08x\n"), hr); else trace(_T("SetActionMap() succeeded\n")); } } // if (nCurUser != -1)
else { // we're unassigned, set null
trace(_T("Unassigning...\n"));
// we need an acfor to unassign, so get one if don't have
// one left over from what we just did
if (!lpAcFor) lpAcFor = GetAcFor(0, 0);
if (!lpAcFor) etrace(_T("Couldn't get an acfor for unassignment\n"));
HRESULT hr; hr = lpDID->SetActionMap(lpAcFor, NULL, DIDSAM_NOUSER);
if (FAILED(hr)) etrace1(_T("SetActionMap() failed, returning 0x%08x\n"), hr); else trace(_T("SetActionMap() succeeded\n")); } }
int CConfigWnd::GetNumUsers() { return m_uig.GetNumUserNames(); }
int CConfigWnd::GetCurUser(int nPage) { return GetElement(nPage).nCurUser; }
|