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

1907 lines
50 KiB

  1. //-----------------------------------------------------------------------------
  2. // File: cdiacpage.cpp
  3. //
  4. // Desc: CDIDeviceActionConfigPage implements the page object used by the UI.
  5. // A page covers the entire UI minus the device tabs and the bottons at
  6. // the bottom. The information window, player combo-box, genre combo-
  7. // box, action list tree, and device view window are all managed by
  8. // the page.
  9. //
  10. // Copyright (C) 1999-2000 Microsoft Corporation. All Rights Reserved.
  11. //-----------------------------------------------------------------------------
  12. #include "common.hpp"
  13. #include <initguid.h>
  14. DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
  15. // {D0B5C9AE-966F-4510-B955-4D2482C5EB1B}
  16. DEFINE_GUID(GUID_ActionItem,
  17. 0xd0b5c9ae, 0x966f, 0x4510, 0xb9, 0x55, 0x4d, 0x24, 0x82, 0xc5, 0xeb, 0x1b);
  18. #define DISEM_TYPE_MASK ( 0x00000600 )
  19. #define DISEM_REL_MASK ( 0x00000100 )
  20. #define DISEM_REL_SHIFT ( 8 )
  21. #define DISEM_TYPE_AXIS 0x00000200
  22. #define DISEM_TYPE_BUTTON 0x00000400
  23. #define DISEM_TYPE_POV 0x00000600
  24. #define DEVICE_POLLING_INTERVAL 10
  25. #define DEVICE_POLLING_AXIS_MIN 0
  26. #define DEVICE_POLLING_AXIS_MAX 100
  27. #define DEVICE_POLLING_AXIS_MINDELTA 3
  28. #define DEVICE_POLLING_AXIS_SIGNIFICANT 40
  29. #define DEVICE_POLLING_AXIS_ACCUMULATION 20
  30. #define DEVICE_POLLING_ACBUF_START_INDEX 3
  31. #define DEVICE_POLLING_WHEEL_SCALE_FACTOR 3
  32. // For WINMM.DLL
  33. HINSTANCE g_hWinMmDLL = NULL;
  34. FUNCTYPE_timeSetEvent g_fptimeSetEvent = NULL;
  35. //QueryInterface
  36. STDMETHODIMP CDIDeviceActionConfigPage::QueryInterface(REFIID iid, LPVOID* ppv)
  37. {
  38. //null the out param
  39. *ppv = NULL;
  40. if ((iid == IID_IUnknown) || (iid == IID_IDIDeviceActionConfigPage))
  41. {
  42. *ppv = this;
  43. AddRef();
  44. return S_OK;
  45. }
  46. return E_NOINTERFACE;
  47. }
  48. //AddRef
  49. STDMETHODIMP_(ULONG) CDIDeviceActionConfigPage::AddRef()
  50. {
  51. return InterlockedIncrement(&m_cRef);
  52. }
  53. //Release
  54. STDMETHODIMP_(ULONG) CDIDeviceActionConfigPage::Release()
  55. {
  56. if (InterlockedDecrement(&m_cRef) == 0)
  57. {
  58. delete this;
  59. return 0;
  60. }
  61. return m_cRef;
  62. }
  63. //constructor
  64. CDIDeviceActionConfigPage::CDIDeviceActionConfigPage() :
  65. m_pDeviceUI(NULL), m_puig(NULL), m_pUIFrame(NULL),
  66. m_cRef(1), m_lpDiac(NULL), m_State(CFGSTATE_NORMAL),
  67. m_pCurControl(NULL),
  68. m_tszIBText(NULL), m_pbmIB(NULL), m_pbmIB2(NULL),
  69. m_pbmRelAxesGlyph(NULL), m_pbmAbsAxesGlyph(NULL), m_pbmButtonGlyph(NULL),
  70. m_pbmHatGlyph(NULL), m_pbmCheckGlyph(NULL), m_pbmCheckGlyphDark(NULL),
  71. m_pRelAxesParent(NULL), m_pAbsAxesParent(NULL), m_pButtonParent(NULL),
  72. m_pHatParent(NULL), m_pUnknownParent(NULL),
  73. m_bFirstDeviceData(TRUE), m_cbDeviceDataSize(0), m_nOnDeviceData(0),
  74. m_dwLastControlType(0),
  75. m_nPageIndex(-1)
  76. {
  77. tracescope(__ts, _T("CDIDeviceActionConfigPage::CDIDeviceActionConfigPage()\n"));
  78. m_pDeviceData[0] = NULL;
  79. m_pDeviceData[1] = NULL;
  80. }
  81. //destructor
  82. CDIDeviceActionConfigPage::~CDIDeviceActionConfigPage()
  83. {
  84. tracescope(__ts, _T("CDIDeviceActionConfigPage::~CDIDeviceActionConfigPage()\n"));
  85. // Unattach the parent from the tooltip window so it won't get destroyed.
  86. SetParent(CFlexWnd::s_ToolTip.m_hWnd, NULL);
  87. if (m_hWnd != NULL)
  88. Destroy();
  89. FreeResources();
  90. delete m_pDeviceUI;
  91. for (int c = 0; c < 2; c++)
  92. if (m_pDeviceData[c] != NULL)
  93. free(m_pDeviceData[c]);
  94. if (m_lpDID != NULL)
  95. {
  96. m_lpDID->Unacquire();
  97. m_lpDID->Release();
  98. }
  99. m_lpDID = NULL;
  100. }
  101. STDMETHODIMP CDIDeviceActionConfigPage::Create(DICFGPAGECREATESTRUCT *pcs)
  102. {
  103. tracescope(__ts, _T("CDIDeviceActionConfigPage::Create()\n"));
  104. if (pcs == NULL)
  105. return E_INVALIDARG;
  106. DICFGPAGECREATESTRUCT &cs = *pcs;
  107. // validate/save uig and uif
  108. m_puig = pcs->pUIGlobals;
  109. m_pUIFrame = pcs->pUIFrame;
  110. if (m_puig == NULL || m_pUIFrame == NULL)
  111. return E_INVALIDARG;
  112. // save page index
  113. m_nPageIndex = pcs->nPage;
  114. assert(m_nPageIndex >= 0);
  115. // create deviceui with uig, or fail
  116. m_pDeviceUI = new CDeviceUI(*m_puig, *m_pUIFrame);
  117. if (m_pDeviceUI == NULL)
  118. return E_FAIL;
  119. // save the device instance
  120. m_didi = cs.didi;
  121. m_lpDID = cs.lpDID;
  122. if (m_lpDID != NULL)
  123. m_lpDID->AddRef();
  124. // create the window
  125. HWND hWnd = NULL;
  126. assert(m_puig != NULL);
  127. //@@BEGIN_MSINTERNAL
  128. #ifdef DDKBUILD
  129. BOOL bAllowEditLayout = m_puig->QueryAllowEditLayout();
  130. #endif
  131. //@@END_MSINTERNAL
  132. RECT rect = {0, 0, 1, 1};
  133. hWnd = CFlexWnd::Create(cs.hParentWnd, rect, FALSE);
  134. // return the handle
  135. cs.hPageWnd = hWnd;
  136. assert(m_puig != NULL);
  137. // Create the information box
  138. m_InfoBox.Create(m_hWnd, g_InfoWndRect, TRUE);
  139. m_InfoBox.SetFont((HFONT)m_puig->GetFont(UIE_USERNAMES));
  140. m_InfoBox.SetColors(m_puig->GetTextColor(UIE_USERNAMES),
  141. m_puig->GetBkColor(UIE_USERNAMES),
  142. m_puig->GetTextColor(UIE_USERNAMESEL),
  143. m_puig->GetBkColor(UIE_USERNAMESEL),
  144. m_puig->GetBrushColor(UIE_USERNAMES),
  145. m_puig->GetPenColor(UIE_USERNAMES));
  146. SetAppropriateDefaultText();
  147. // Create the check box only if this is a keyboard device.
  148. if (LOBYTE(LOWORD(m_didi.dwDevType)) == DI8DEVTYPE_KEYBOARD)
  149. {
  150. m_CheckBox.Create(m_hWnd, g_CheckBoxRect, FALSE);
  151. m_CheckBox.SetNotify(m_hWnd);
  152. m_CheckBox.SetFont((HFONT)m_puig->GetFont(UIE_USERNAMES));
  153. m_CheckBox.SetColors(m_puig->GetTextColor(UIE_USERNAMES),
  154. m_puig->GetBkColor(UIE_USERNAMES),
  155. m_puig->GetTextColor(UIE_USERNAMESEL),
  156. m_puig->GetBkColor(UIE_USERNAMESEL),
  157. m_puig->GetBrushColor(UIE_USERNAMES),
  158. m_puig->GetPenColor(UIE_USERNAMES));
  159. TCHAR tszResourceString[MAX_PATH];
  160. LoadString(g_hModule, IDS_SORTASSIGNED, tszResourceString, MAX_PATH);
  161. m_CheckBox.SetText(tszResourceString);
  162. m_CheckBox.SetCheck(TRUE);
  163. ::ShowWindow(m_CheckBox.m_hWnd, SW_SHOW);
  164. }
  165. // create the username dropdown if necessary
  166. FLEXCOMBOBOXCREATESTRUCT cbcs;
  167. cbcs.dwSize = sizeof(FLEXCOMBOBOXCREATESTRUCT);
  168. cbcs.dwFlags = FCBF_DEFAULT;
  169. cbcs.dwListBoxFlags = FCBF_DEFAULT|FLBF_INTEGRALHEIGHT;
  170. cbcs.hWndParent = m_hWnd;
  171. cbcs.hWndNotify = m_hWnd;
  172. cbcs.bVisible = TRUE;
  173. cbcs.rect = g_UserNamesRect;
  174. cbcs.hFont = (HFONT)m_puig->GetFont(UIE_USERNAMES);
  175. cbcs.rgbText = m_puig->GetTextColor(UIE_USERNAMES);
  176. cbcs.rgbBk = m_puig->GetBkColor(UIE_USERNAMES);
  177. cbcs.rgbSelText = m_puig->GetTextColor(UIE_USERNAMESEL);
  178. cbcs.rgbSelBk = m_puig->GetBkColor(UIE_USERNAMESEL);
  179. cbcs.rgbFill = m_puig->GetBrushColor(UIE_USERNAMES);
  180. cbcs.rgbLine = m_puig->GetPenColor(UIE_USERNAMES);
  181. cbcs.nSBWidth = 11;
  182. if (m_puig->GetNumUserNames() > 0 && m_hWnd != NULL
  183. //@@BEGIN_MSINTERNAL
  184. #ifdef DDKBUILD
  185. && !m_puig->QueryAllowEditLayout()
  186. #endif
  187. //@@END_MSINTERNAL
  188. )
  189. {
  190. for (int i = 0, n = m_puig->GetNumUserNames(); i < n; i++)
  191. m_UserNames.AddString(SAFESTR(m_puig->GetUserName(i)));
  192. m_UserNames.AddString(SAFESTR(_T("(unassigned)")));
  193. m_UserNames.Create(&cbcs);
  194. int nUser = m_pUIFrame->GetCurUser(m_nPageIndex);
  195. if (nUser == -1)
  196. nUser = m_puig->GetNumUserNames();
  197. m_UserNames.SetSel(nUser);
  198. } else
  199. if (m_hWnd != NULL)
  200. m_UserNames.SetSel(0); // If only 1 user, still must set selection to 0 or we get error later.
  201. // If we are in view mode, set username combobox to read only so user can't change its value.
  202. if (!m_puig->InEditMode())
  203. m_UserNames.SetReadOnly(TRUE);
  204. if (m_puig->GetNumMasterAcFors() > 1 && m_hWnd != NULL)
  205. {
  206. for (int i = 0, n = m_puig->GetNumMasterAcFors(); i < n; i++)
  207. m_Genres.AddString(SAFESTR(m_puig->RefMasterAcFor(i).tszActionMap));
  208. cbcs.rect = g_GenresRect;
  209. m_Genres.Create(&cbcs);
  210. m_Genres.SetSel(m_pUIFrame->GetCurGenre());
  211. }
  212. // return success/fail
  213. return hWnd != NULL ? S_OK : E_FAIL;
  214. }
  215. STDMETHODIMP CDIDeviceActionConfigPage::Show(LPDIACTIONFORMATW lpDiActFor)
  216. {
  217. // save the format pointer
  218. m_lpDiac = lpDiActFor;
  219. // force tree init
  220. InitTree(TRUE);
  221. // show the assignments for the controls
  222. SetControlAssignments();
  223. // show the assignment for the current control
  224. ShowCurrentControlAssignment();
  225. // Sort the list if check box is checked.
  226. if (m_CheckBox.GetCheck())
  227. m_pDeviceUI->GetCurView()->SortAssigned(TRUE);
  228. // show the window
  229. if (m_hWnd != NULL)
  230. ShowWindow(m_hWnd, SW_SHOW);
  231. SetFocus(m_hWnd);
  232. CFlexWnd::s_CurrPageHwnd = m_hWnd;
  233. return S_OK;
  234. }
  235. STDMETHODIMP CDIDeviceActionConfigPage::Hide()
  236. {
  237. // clear the tree
  238. ClearTree();
  239. // null the format pointer
  240. m_lpDiac = NULL;
  241. // hide the window
  242. if (m_hWnd != NULL)
  243. ShowWindow(m_hWnd, SW_HIDE);
  244. // If we are in the assign state, exit it.
  245. if (m_State == CFGSTATE_ASSIGN)
  246. ExitAssignState();
  247. return S_OK;
  248. }
  249. void CDIDeviceActionConfigPage::InitIB()
  250. {
  251. RECT z = {0,0,0,0};
  252. SIZE bsize = {0,0};
  253. m_rectIB = z;
  254. if (m_pbmIB != NULL)
  255. {
  256. if (m_pbmIB->GetSize(&bsize))
  257. {
  258. m_rectIB.right = bsize.cx * 2;
  259. m_rectIB.bottom = bsize.cy;
  260. }
  261. }
  262. const int IBORIGINX = 200, IBORIGINY = 394,
  263. IBTEXTMARGINLEFT = 5;
  264. POINT ptIBOrigin = {IBORIGINX, IBORIGINY};
  265. m_tszIBText = _T("Click here to see different views of your controller.");
  266. SIZE tsize = GetTextSize(m_tszIBText, (HFONT)m_puig->GetFont(UIE_VIEWSEL));
  267. m_ptIBOffset.x = 0;
  268. m_ptIBOffset.y = 0;
  269. int tofs = 0;
  270. if (m_rectIB.bottom < tsize.cy)
  271. {
  272. m_rectIB.bottom = tsize.cy;
  273. m_ptIBOffset.y = (tsize.cy - bsize.cy) / 2;
  274. }
  275. else if (tsize.cy < m_rectIB.bottom)
  276. tofs = (bsize.cy - tsize.cy) / 2;
  277. m_rectIB.right += tsize.cx;
  278. if (m_pbmIB != NULL)
  279. m_rectIB.right += IBTEXTMARGINLEFT * 2;
  280. OffsetRect(&m_rectIB, ptIBOrigin.x, ptIBOrigin.y);
  281. m_ptIBOffset.x += ptIBOrigin.x;
  282. m_ptIBOffset.y += ptIBOrigin.y;
  283. m_ptIBOffset2.x = m_rectIB.right - bsize.cx;
  284. m_ptIBOffset2.y = m_ptIBOffset.y;
  285. m_rectIBText = m_rectIB;
  286. if (m_pbmIB != NULL)
  287. m_rectIBText.left += IBTEXTMARGINLEFT + bsize.cx;
  288. if (m_pbmIB2 != NULL)
  289. m_rectIBText.right -= IBTEXTMARGINLEFT + bsize.cx;
  290. m_rectIBText.top += tofs;
  291. // Inialize the two RECTs representing the two arrow bitmaps
  292. m_rectIBLeft = m_rectIBRight = m_rectIB;
  293. m_rectIBLeft.right = m_rectIBText.left;
  294. m_rectIBRight.left = m_rectIBText.right;
  295. }
  296. void CDIDeviceActionConfigPage::OnInit()
  297. {
  298. tracescope(__ts, _T("CDIDeviceActionConfigPage::OnInit()\n"));
  299. // init resources
  300. InitResources();
  301. // init IB
  302. InitIB();
  303. // initialize the device UI
  304. m_pDeviceUI->Init(m_didi, m_lpDID, m_hWnd, this);
  305. // initialize the device
  306. InitDevice();
  307. // Start a one-shot timer for click to pick
  308. if (g_fptimeSetEvent)
  309. g_fptimeSetEvent(DEVICE_POLLING_INTERVAL, DEVICE_POLLING_INTERVAL,
  310. CDIDeviceActionConfigPage::DeviceTimerProc, (DWORD_PTR)m_hWnd, TIME_ONESHOT);
  311. // create the tree
  312. CAPTIONLOOK cl;
  313. cl.dwMask = CLMF_TEXTCOLOR | CLMF_FONT | CLMF_LINECOLOR;
  314. cl.rgbTextColor = m_puig->GetTextColor(UIE_CALLOUT);
  315. cl.rgbLineColor = m_puig->GetPenColor(UIE_BORDER);
  316. cl.hFont = (HFONT)m_puig->GetFont(UIE_ACTION);
  317. m_Tree.SetDefCaptionLook(cl);
  318. cl.rgbTextColor = m_puig->GetTextColor(UIE_CALLOUTHIGH);
  319. m_Tree.SetDefCaptionLook(cl, TRUE);
  320. m_Tree.SetBkColor(RGB(0,0,0));
  321. if (m_puig->InEditMode())
  322. {
  323. m_Tree.Create(m_hWnd, g_TreeRect, TRUE, TRUE);
  324. m_Tree.SetScrollBarColors(
  325. m_puig->GetBrushColor(UIE_SBTRACK),
  326. m_puig->GetBrushColor(UIE_SBTHUMB),
  327. m_puig->GetPenColor(UIE_SBBUTTON));
  328. }
  329. }
  330. void CDIDeviceActionConfigPage::InitResources()
  331. {
  332. // create glyphs
  333. if (!m_pbmRelAxesGlyph)
  334. m_pbmRelAxesGlyph = CBitmap::CreateFromResource(g_hModule, IDB_AXESGLYPH);
  335. if (!m_pbmAbsAxesGlyph)
  336. m_pbmAbsAxesGlyph = CBitmap::CreateFromResource(g_hModule, IDB_AXESGLYPH);
  337. if (!m_pbmButtonGlyph)
  338. m_pbmButtonGlyph = CBitmap::CreateFromResource(g_hModule, IDB_BUTTONGLYPH);
  339. if (!m_pbmHatGlyph)
  340. m_pbmHatGlyph = CBitmap::CreateFromResource(g_hModule, IDB_HATGLYPH);
  341. if (!m_pbmCheckGlyph)
  342. m_pbmCheckGlyph = CBitmap::CreateFromResource(g_hModule, IDB_CHECKGLYPH);
  343. if (!m_pbmCheckGlyphDark)
  344. m_pbmCheckGlyphDark = CBitmap::CreateFromResource(g_hModule, IDB_CHECKGLYPHDARK);
  345. // create IB bitmaps
  346. if (!m_pbmIB)
  347. m_pbmIB = CBitmap::CreateFromResource(g_hModule, IDB_IB);
  348. if (!m_pbmIB2)
  349. m_pbmIB2 = CBitmap::CreateFromResource(g_hModule, IDB_IB2);
  350. }
  351. void CDIDeviceActionConfigPage::FreeResources()
  352. {
  353. if (m_pbmRelAxesGlyph)
  354. delete m_pbmRelAxesGlyph;
  355. if (m_pbmAbsAxesGlyph)
  356. delete m_pbmAbsAxesGlyph;
  357. if (m_pbmButtonGlyph)
  358. delete m_pbmButtonGlyph;
  359. if (m_pbmHatGlyph)
  360. delete m_pbmHatGlyph;
  361. if (m_pbmCheckGlyph)
  362. delete m_pbmCheckGlyph;
  363. if (m_pbmCheckGlyphDark)
  364. delete m_pbmCheckGlyphDark;
  365. if (m_pbmIB)
  366. delete m_pbmIB;
  367. if (m_pbmIB2)
  368. delete m_pbmIB2;
  369. m_pbmRelAxesGlyph = NULL;
  370. m_pbmAbsAxesGlyph = NULL;
  371. m_pbmButtonGlyph = NULL;
  372. m_pbmHatGlyph = NULL;
  373. m_pbmCheckGlyph = NULL;
  374. m_pbmCheckGlyphDark = NULL;
  375. m_pbmIB = NULL;
  376. m_pbmIB2 = NULL;
  377. }
  378. void CDIDeviceActionConfigPage::ClearTree()
  379. {
  380. m_Tree.FreeAll();
  381. m_pRelAxesParent = NULL;
  382. m_pAbsAxesParent = NULL;
  383. m_pButtonParent = NULL;
  384. m_pHatParent = NULL;
  385. m_pUnknownParent = NULL;
  386. m_dwLastControlType = 0;
  387. }
  388. void CDIDeviceActionConfigPage::InitTree(BOOL bForceInit)
  389. {
  390. // get type of control
  391. DWORD dwControlType = 0;
  392. if (m_pCurControl && m_pCurControl->IsOffsetAssigned())
  393. {
  394. DWORD dwObjId = m_pCurControl->GetOffset();
  395. if (dwObjId & DIDFT_RELAXIS)
  396. dwControlType = DIDFT_RELAXIS;
  397. else if (dwObjId & DIDFT_ABSAXIS)
  398. dwControlType = DIDFT_ABSAXIS;
  399. else if (dwObjId & DIDFT_BUTTON)
  400. dwControlType = DIDFT_BUTTON;
  401. else if (dwObjId & DIDFT_POV)
  402. dwControlType = DIDFT_POV;
  403. }
  404. // Turn off the tree's readonly flag if we are in the assign state.
  405. // We will turn it on later if current control's action has DIA_APPFIXED.
  406. if (m_State == CFGSTATE_NORMAL)
  407. m_Tree.SetReadOnly(TRUE);
  408. else
  409. m_Tree.SetReadOnly(FALSE);
  410. // if this control type is the same as the last, do nothing,
  411. // unless we're force init
  412. if (m_dwLastControlType == dwControlType && !bForceInit && m_State)
  413. return;
  414. // delete the whole tree
  415. ClearTree();
  416. // can't use tree if there is no diac or action array
  417. if (m_lpDiac == NULL || m_lpDiac->rgoAction == NULL)
  418. return;
  419. // also can't use if we don't have a control type
  420. if (dwControlType == 0)
  421. return;
  422. // prepare margin rects
  423. RECT labelmargin = {14, 6, 3, 3};
  424. RECT itemmargin = {14, 1, 3, 2};
  425. // set default indents
  426. m_Tree.SetRootChildIndent(5);
  427. m_Tree.SetDefChildIndent(12);
  428. // add the control type sections
  429. m_Tree.SetDefMargin(labelmargin);
  430. TCHAR tszResourceString[MAX_PATH];
  431. switch (dwControlType)
  432. {
  433. case DIDFT_RELAXIS:
  434. LoadString(g_hModule, IDS_AXISACTIONS, tszResourceString, MAX_PATH);
  435. m_pRelAxesParent = m_Tree.DefAddItem(tszResourceString);
  436. break;
  437. case DIDFT_ABSAXIS:
  438. LoadString(g_hModule, IDS_AXISACTIONS, tszResourceString, MAX_PATH);
  439. m_pAbsAxesParent = m_Tree.DefAddItem(tszResourceString);
  440. break;
  441. case DIDFT_BUTTON:
  442. LoadString(g_hModule, IDS_BUTTONACTIONS, tszResourceString, MAX_PATH);
  443. m_pButtonParent = m_Tree.DefAddItem(tszResourceString);
  444. break;
  445. case DIDFT_POV:
  446. LoadString(g_hModule, IDS_POVACTIONS, tszResourceString, MAX_PATH);
  447. m_pHatParent = m_Tree.DefAddItem(tszResourceString);
  448. break;
  449. default:
  450. return;
  451. }
  452. // populate the tree
  453. m_Tree.SetDefMargin(itemmargin);
  454. for (unsigned int i = 0; i < m_lpDiac->dwNumActions; i++)
  455. {
  456. DIACTIONW *pAction = m_lpDiac->rgoAction + i;
  457. CFTItem *pItem = NULL;
  458. if (pAction == NULL)
  459. continue;
  460. switch (pAction->dwSemantic & DISEM_TYPE_MASK)
  461. {
  462. case DISEM_TYPE_AXIS:
  463. // Must distinguish between relative and absolute
  464. switch((pAction->dwSemantic & DISEM_REL_MASK) >> DISEM_REL_SHIFT)
  465. {
  466. case 0: pItem = m_pAbsAxesParent; break;
  467. case 1: pItem = m_pRelAxesParent; break;
  468. }
  469. break;
  470. case DISEM_TYPE_BUTTON: pItem = m_pButtonParent; break;
  471. case DISEM_TYPE_POV: pItem = m_pHatParent; break;
  472. }
  473. if (pItem == NULL)
  474. continue;
  475. // Add action with this name
  476. CFTItem *pAlready = GetItemWithActionNameAndSemType(pAction->lptszActionName, pAction->dwSemantic);
  477. if (!pAlready)
  478. {
  479. LPTSTR acname = AllocLPTSTR(pAction->lptszActionName);
  480. pItem = m_Tree.DefAddItem(acname, pItem, ATTACH_LASTCHILD); // This might return NULL.
  481. free(acname);
  482. if (pItem)
  483. pItem->SetUserData((LPVOID)(new RGLPDIACW));
  484. }
  485. else
  486. {
  487. pItem = pAlready;
  488. }
  489. if (pItem == NULL)
  490. continue;
  491. pItem->SetUserGUID(GUID_ActionItem);
  492. RGLPDIACW *pacs = (RGLPDIACW *)pItem->GetUserData();
  493. if (pacs)
  494. pacs->SetAtGrow(pacs->GetSize(), pAction);
  495. if (pAlready)
  496. {
  497. // The tree already has an action with this name. Check the DIA_APPFIXED flag for each DIACTION
  498. // that this item holds.
  499. DWORD dwNumActions = GetNumItemLpacs(pItem);
  500. for (DWORD i = 0; i < dwNumActions; ++i)
  501. {
  502. LPDIACTIONW lpExistingAc = GetItemLpac(pItem, i);
  503. // If the DIACTION that is assigned to this device has DIA_APPFIXED flag, then
  504. // the other must have it too.
  505. if (lpExistingAc && IsEqualGUID(lpExistingAc->guidInstance, m_didi.guidInstance))
  506. {
  507. if (lpExistingAc->dwFlags & DIA_APPFIXED)
  508. {
  509. // If this DIACTION has DIA_APPFIXED, then all DIACTIONs must have it too.
  510. for (DWORD j = 0; j < dwNumActions; ++j)
  511. {
  512. LPDIACTIONW lpChangeAc = GetItemLpac(pItem, j);
  513. if (lpChangeAc)
  514. lpChangeAc->dwFlags |= DIA_APPFIXED;
  515. }
  516. }
  517. break; // Break the loop since we already found the DIACTION that is assigned.
  518. }
  519. }
  520. } // if (pAlready)
  521. }
  522. // show all
  523. m_Tree.GetRoot()->ExpandAll();
  524. m_dwLastControlType = dwControlType;
  525. }
  526. int CompareActionNames(LPCWSTR acname1, LPCWSTR acname2)
  527. {
  528. #ifdef CFGUI__COMPAREACTIONNAMES_CASE_INSENSITIVE
  529. return _wcsicmp(acname1, acname2);
  530. #else
  531. return wcscmp(acname1, acname2);
  532. #endif
  533. }
  534. CFTItem *CDIDeviceActionConfigPage::GetItemWithActionNameAndSemType(LPCWSTR acname, DWORD dwSemantic)
  535. {
  536. CFTItem *pItem = m_Tree.GetFirstItem();
  537. for (; pItem != NULL; pItem = pItem->GetNext())
  538. {
  539. if (!pItem->IsUserGUID(GUID_ActionItem))
  540. continue;
  541. LPDIACTIONW lpac = GetItemLpac(pItem);
  542. if (!lpac)
  543. continue;
  544. // Check semantic type
  545. if ((lpac->dwSemantic & DISEM_TYPE_MASK) != (dwSemantic & DISEM_TYPE_MASK))
  546. continue;
  547. // If both are axis, check for relative/absolute
  548. if ((lpac->dwSemantic & DISEM_TYPE_MASK) == DISEM_TYPE_AXIS)
  549. if ((lpac->dwSemantic & DISEM_REL_MASK) != (dwSemantic & DISEM_REL_MASK))
  550. continue;
  551. // Check name
  552. if (CompareActionNames(lpac->lptszActionName, acname) == 0)
  553. return pItem;
  554. }
  555. return NULL;
  556. }
  557. void CDIDeviceActionConfigPage::OnPaint(HDC hDC)
  558. {
  559. TCHAR tszResourceString[MAX_PATH];
  560. CPaintHelper ph(*m_puig, hDC);
  561. ph.SetBrush(UIB_BLACK);
  562. RECT rect;
  563. GetClientRect(&rect);
  564. ph.Rectangle(rect, UIR_SOLID);
  565. ph.SetText(UIC_BORDER, UIC_BLACK);
  566. //@@BEGIN_MSINTERNAL
  567. #ifdef DDKBUILD
  568. if (!m_puig->QueryAllowEditLayout())
  569. #endif
  570. //@@END_MSINTERNAL
  571. {
  572. rect = g_UserNamesTitleRect;
  573. LoadString(g_hModule, IDS_PLAYER_TITLE, tszResourceString, MAX_PATH);
  574. DrawText(hDC, tszResourceString, -1, &rect, DT_CENTER|DT_NOCLIP|DT_NOPREFIX);
  575. }
  576. if (m_puig->GetNumMasterAcFors() > 1)
  577. {
  578. rect = g_GenresTitleRect;
  579. LoadString(g_hModule, IDS_GENRE_TITLE, tszResourceString, MAX_PATH);
  580. DrawText(hDC, tszResourceString, -1, &rect, DT_CENTER|DT_NOCLIP|DT_NOPREFIX);
  581. }
  582. // Draw tree window title and outline if we are in edit mode.
  583. if (m_puig->InEditMode())
  584. {
  585. COLORREF BorderColor = m_puig->GetColor(UIC_BORDER);
  586. if (m_Tree.GetReadOnly())
  587. BorderColor = RGB(GetRValue(BorderColor)>>1, GetGValue(BorderColor)>>1, GetBValue(BorderColor)>>1);
  588. ::SetTextColor(hDC, BorderColor); // Use the muted color if tree is read only.
  589. // Draw tree window title (Available Actions)
  590. rect = g_TreeTitleRect;
  591. LoadString(g_hModule, IDS_AVAILABLEACTIONS_TITLE, tszResourceString, MAX_PATH);
  592. DrawText(hDC, tszResourceString, -1, &rect, DT_CENTER|DT_NOCLIP|DT_NOPREFIX);
  593. // Draw tree window outline
  594. HGDIOBJ hPen, hOldPen;
  595. if (m_Tree.GetReadOnly())
  596. {
  597. hPen = CreatePen(PS_SOLID, 0, BorderColor);
  598. hOldPen = ::SelectObject(hDC, hPen);
  599. }
  600. else
  601. ph.SetPen(UIP_BORDER);
  602. RECT rc = g_TreeRect;
  603. InflateRect(&rc, 1, 1);
  604. Rectangle(hDC, rc.left, rc.top, rc.right, rc.bottom);
  605. if (m_Tree.GetReadOnly())
  606. {
  607. ::SelectObject(hDC, hOldPen);
  608. DeleteObject(hPen);
  609. }
  610. }
  611. if (m_pDeviceUI->GetNumViews() < 2)
  612. return;
  613. if (m_pbmIB != NULL)
  614. m_pbmIB->Draw(hDC, m_ptIBOffset);
  615. if (m_pbmIB2 != NULL)
  616. m_pbmIB2->Draw(hDC, m_ptIBOffset2);
  617. if (m_tszIBText != NULL)
  618. {
  619. ph.SetElement(UIE_VIEWSEL);
  620. RECT rect = m_rectIBText;
  621. DrawText(hDC, m_tszIBText, -1, &rect, DT_NOCLIP | DT_NOPREFIX);
  622. }
  623. }
  624. void CDIDeviceActionConfigPage::SetCurrentControl(CDeviceControl *pControl)
  625. {
  626. // If the new control is the same as the old, no need to do anything.
  627. if (m_pCurControl == pControl)
  628. return;
  629. if (m_pCurControl != NULL)
  630. {
  631. m_pCurControl->Unhighlight();
  632. // If we don't have a current control, then invalidate the view so that the old callout can be repainted.
  633. // If there is a current control, the view will be invalidated by Highlight().
  634. if (!pControl)
  635. m_pCurControl->Invalidate();
  636. }
  637. m_pCurControl = pControl;
  638. if (m_pCurControl != NULL)
  639. m_pCurControl->Highlight();
  640. ShowCurrentControlAssignment();
  641. }
  642. CFTItem *CDIDeviceActionConfigPage::GetItemForActionAssignedToControl(CDeviceControl *pControl)
  643. {
  644. if (!pControl)
  645. return NULL;
  646. // find the item for the action assigned to this control, if any
  647. CFTItem *pItem = m_Tree.GetFirstItem();
  648. for (; pItem != NULL; pItem = pItem->GetNext())
  649. {
  650. if (!pItem->IsUserGUID(GUID_ActionItem))
  651. continue;
  652. for (int i = 0, n = GetNumItemLpacs(pItem); i < n; i++)
  653. {
  654. LPDIACTIONW lpac = GetItemLpac(pItem, i);
  655. if (!lpac)
  656. continue;
  657. if (IsEqualGUID(lpac->guidInstance, m_didi.guidInstance) &&
  658. GetOffset(lpac) == pControl->GetOffset())
  659. return pItem;
  660. }
  661. }
  662. return NULL;
  663. }
  664. int CDIDeviceActionConfigPage::GetNumItemLpacs(CFTItem *pItem)
  665. {
  666. if (pItem == NULL)
  667. return 0;
  668. RGLPDIACW *pacs = (RGLPDIACW *)pItem->GetUserData();
  669. if (!pacs)
  670. return 0;
  671. else
  672. return pacs->GetSize();
  673. }
  674. LPDIACTIONW CDIDeviceActionConfigPage::GetItemLpac(CFTItem *pItem, int i)
  675. {
  676. if (pItem == NULL)
  677. return NULL;
  678. RGLPDIACW *pacs = (RGLPDIACW *)pItem->GetUserData();
  679. if (!pacs || i < 0 || i >= pacs->GetSize())
  680. return NULL;
  681. else
  682. return pacs->GetAt(i);
  683. }
  684. void CDIDeviceActionConfigPage::ShowCurrentControlAssignment()
  685. {
  686. // init the tree
  687. InitTree();
  688. // if we don't have a control...
  689. if (m_pCurControl == NULL)
  690. {
  691. // select nothing
  692. m_Tree.SetCurSel(NULL);
  693. return;
  694. }
  695. // find the item for the action assigned to this control, if any
  696. CFTItem *pItem = GetItemForActionAssignedToControl(m_pCurControl);
  697. // if we didn't find a match...
  698. if (!pItem)
  699. {
  700. // select nothing
  701. m_Tree.SetCurSel(NULL);
  702. return;
  703. }
  704. // We need to check if the action this control is assigned to has DIA_APPFIXED flag.
  705. // If it does, this control cannot be remapped to another action.
  706. // We prevent this by setting the tree control to read-only, so it can't receive any clicks.
  707. LPDIACTIONW lpAc = GetItemLpac(pItem); // Get the action
  708. if (lpAc && (lpAc->dwFlags & DIA_APPFIXED))
  709. m_Tree.SetReadOnly(TRUE);
  710. // otherwise, show item and select it
  711. pItem->EnsureVisible();
  712. m_Tree.SetCurSel(pItem);
  713. }
  714. void CDIDeviceActionConfigPage::DeviceUINotify(const DEVICEUINOTIFY &uin)
  715. {
  716. switch (uin.msg)
  717. {
  718. case DEVUINM_NUMVIEWSCHANGED:
  719. Invalidate();
  720. break;
  721. case DEVUINM_SELVIEW:
  722. // set the view
  723. m_pDeviceUI->SetView(uin.selview.nView);
  724. // show the assignments for the controls
  725. SetControlAssignments();
  726. // select nothing
  727. SetCurrentControl(NULL);
  728. break;
  729. case DEVUINM_ONCONTROLDESTROY:
  730. if (uin.control.pControl == m_pCurControl)
  731. m_pCurControl = NULL;
  732. break;
  733. case DEVUINM_CLICK:
  734. ExitAssignState();
  735. switch (uin.from)
  736. {
  737. case DEVUINFROM_CONTROL:
  738. SetCurrentControl(uin.control.pControl);
  739. SetAppropriateDefaultText();
  740. break;
  741. case DEVUINFROM_VIEWWND:
  742. break;
  743. }
  744. break;
  745. case DEVUINM_DOUBLECLICK:
  746. switch (uin.from)
  747. {
  748. case DEVUINFROM_CONTROL:
  749. EnterAssignState();
  750. break;
  751. }
  752. break;
  753. case DEVUINM_MOUSEOVER:
  754. SetAppropriateDefaultText();
  755. break;
  756. case DEVUINM_RENEWDEVICE:
  757. HWND hParent = GetParent(m_hWnd);
  758. CConfigWnd *pCfgWnd = (CConfigWnd *)GetFlexWnd(hParent);
  759. if (pCfgWnd)
  760. {
  761. LPDIRECTINPUTDEVICE8W lpDID = pCfgWnd->RenewDevice(m_didi.guidInstance);
  762. if (lpDID)
  763. {
  764. // Destroy the device instance we have
  765. if (m_lpDID) m_lpDID->Release();
  766. lpDID->AddRef();
  767. m_lpDID = lpDID;
  768. }
  769. m_pDeviceUI->SetDevice(lpDID); // Sets the device pointer in CDeviceUI (no need to AddRef)
  770. }
  771. }
  772. }
  773. void CDIDeviceActionConfigPage::UnassignCallout()
  774. {
  775. // find the item for the action assigned to this control, if any
  776. CFTItem *pItem = GetItemForActionAssignedToControl(m_pCurControl);
  777. if (pItem)
  778. {
  779. LPDIACTIONW lpac = GetItemLpac(pItem);
  780. // Only unassign if the action doesn't have DIA_APPFIXED flag.
  781. if (lpac && !(lpac->dwFlags & DIA_APPFIXED))
  782. {
  783. ActionClick(NULL);
  784. m_Tree.Invalidate();
  785. }
  786. }
  787. // Sort the list if the check box is checked.
  788. if (m_CheckBox.GetCheck())
  789. m_pDeviceUI->GetCurView()->SortAssigned(TRUE);
  790. }
  791. void CDIDeviceActionConfigPage::NullAction(LPDIACTIONW lpac)
  792. {
  793. if (lpac == NULL)
  794. return;
  795. SetInvalid(lpac);
  796. //@@BEGIN_MSINTERNAL
  797. // TODO: find tree view item with this action and indicate unassignment
  798. //@@END_MSINTERNAL
  799. }
  800. void CDIDeviceActionConfigPage::UnassignActionsAssignedTo(const GUID &guidInstance, DWORD dwOffset)
  801. {
  802. if (m_lpDiac == NULL || m_lpDiac->rgoAction == NULL)
  803. return;
  804. if (IsEqualGUID(guidInstance, GUID_NULL))
  805. return;
  806. // assign any actions assigned to this control to nothing
  807. DWORD i;
  808. LPDIACTIONW lpac;
  809. for (i = 0, lpac = m_lpDiac->rgoAction; i < m_lpDiac->dwNumActions; i++, lpac++)
  810. if (IsEqualGUID(guidInstance, lpac->guidInstance) && dwOffset == GetOffset(lpac)/*->dwInternalOffset*/)
  811. {
  812. GlobalUnassignControlAt(guidInstance, dwOffset);
  813. NullAction(lpac);
  814. }
  815. }
  816. void CDIDeviceActionConfigPage::UnassignControl(CDeviceControl *pControl)
  817. {
  818. if (pControl == NULL)
  819. return;
  820. // make sure the control itself indicates unassignment
  821. pControl->SetCaption(g_tszUnassignedControlCaption);
  822. }
  823. void CallUnassignControl(CDeviceControl *pControl, LPVOID pVoid, BOOL bFixed)
  824. {
  825. CDIDeviceActionConfigPage *pThis = (CDIDeviceActionConfigPage *)pVoid;
  826. pThis->UnassignControl(pControl);
  827. }
  828. void CDIDeviceActionConfigPage::GlobalUnassignControlAt(const GUID &guidInstance, DWORD dwOffset)
  829. {
  830. if (IsEqualGUID(guidInstance, GUID_NULL))
  831. return;
  832. if (IsEqualGUID(guidInstance, m_didi.guidInstance))
  833. m_pDeviceUI->DoForAllControlsAtOffset(dwOffset, CallUnassignControl, this);
  834. }
  835. // this function must find whatever control is assigned to this action and unassign it
  836. void CDIDeviceActionConfigPage::UnassignAction(LPDIACTIONW slpac)
  837. {
  838. // call UnassignSpecificAction for each action with the same name
  839. // as this one, including this one
  840. if (slpac == NULL)
  841. return;
  842. CFTItem *pItem = GetItemWithActionNameAndSemType(slpac->lptszActionName, slpac->dwSemantic);
  843. if (!pItem)
  844. return;
  845. RGLPDIACW *pacs = (RGLPDIACW *)pItem->GetUserData();
  846. if (!pacs)
  847. return;
  848. for (int i = 0; i < pacs->GetSize(); i++)
  849. UnassignSpecificAction(pacs->GetAt(i));
  850. }
  851. void CDIDeviceActionConfigPage::UnassignSpecificAction(LPDIACTIONW lpac)
  852. {
  853. if (lpac == NULL)
  854. return;
  855. if (IsEqualGUID(lpac->guidInstance, GUID_NULL))
  856. return;
  857. // if there's a control with this instance/offset, unassign it
  858. UnassignActionsAssignedTo(lpac->guidInstance, GetOffset(lpac)/*->dwInternalOffset*/);
  859. GlobalUnassignControlAt(lpac->guidInstance, GetOffset(lpac)/*->dwInternalOffset*/);
  860. // now actually null the action
  861. NullAction(lpac);
  862. }
  863. void CDIDeviceActionConfigPage::AssignCurrentControlToAction(LPDIACTIONW lpac)
  864. {
  865. // if there is a control, unassign it
  866. if (m_pCurControl != NULL)
  867. {
  868. UnassignControl(m_pCurControl);
  869. GUID guidInstance;
  870. DWORD dwOffset;
  871. m_pCurControl->GetInfo(guidInstance, dwOffset);
  872. UnassignActionsAssignedTo(guidInstance, dwOffset);
  873. }
  874. // if there is an action, unassign it
  875. if (lpac != NULL)
  876. UnassignAction(lpac);
  877. // can only continue if we have both
  878. if (lpac == NULL || m_pCurControl == NULL)
  879. return;
  880. // here we should have a control and an action
  881. assert(lpac != NULL);
  882. assert(m_pCurControl != NULL);
  883. // because an action can only be assigned to one control,
  884. // make sure this action is unassigned first
  885. UnassignAction(lpac);
  886. // now actually assign
  887. DWORD ofs;
  888. m_pCurControl->GetInfo(lpac->guidInstance, ofs/*lpac->dwInternalOffset*/);
  889. SetOffset(lpac, ofs);
  890. LPTSTR acname = AllocLPTSTR(lpac->lptszActionName);
  891. m_pCurControl->SetCaption(acname, lpac->dwFlags & DIA_APPFIXED);
  892. free(acname);
  893. // Sort the action list if check box is checked
  894. if (m_CheckBox.GetCheck())
  895. {
  896. m_pDeviceUI->GetCurView()->SortAssigned(TRUE);
  897. // Scroll so that we scroll to make this visible since it might be displaced by sorting.
  898. m_pDeviceUI->GetCurView()->ScrollToMakeControlVisible(m_pCurControl->GetCalloutMaxRect());
  899. }
  900. }
  901. void CDIDeviceActionConfigPage::ActionClick(LPDIACTIONW lpac)
  902. {
  903. if (m_pCurControl != NULL)
  904. {
  905. AssignCurrentControlToAction(lpac);
  906. // Set assignment since other views may have the same callout and
  907. // they need to be updated too.
  908. SetControlAssignments();
  909. }
  910. // Change the state back to normal
  911. ExitAssignState();
  912. }
  913. void CDIDeviceActionConfigPage::SetControlAssignments()
  914. {
  915. assert(!IsEqualGUID(m_didi.guidInstance, GUID_NULL));
  916. m_pDeviceUI->SetAllControlCaptionsTo(g_tszUnassignedControlCaption);
  917. if (m_lpDiac == NULL || m_lpDiac->rgoAction == NULL)
  918. return;
  919. DWORD i;
  920. LPDIACTIONW lpac;
  921. for (i = 0, lpac = m_lpDiac->rgoAction; i < m_lpDiac->dwNumActions; i++)
  922. {
  923. lpac = m_lpDiac->rgoAction + i;
  924. if (IsEqualGUID(lpac->guidInstance, GUID_NULL))
  925. continue;
  926. if (!IsEqualGUID(lpac->guidInstance, m_didi.guidInstance))
  927. continue;
  928. LPTSTR acname = AllocLPTSTR(lpac->lptszActionName);
  929. m_pDeviceUI->SetCaptionForControlsAtOffset(GetOffset(lpac)/*->dwInternalOffset*/, acname, lpac->dwFlags & DIA_APPFIXED);
  930. free(acname);
  931. }
  932. }
  933. void CDIDeviceActionConfigPage::DoViewSel()
  934. {
  935. m_ViewSelWnd.Go(m_hWnd, m_rectIB.left, m_rectIB.top, m_pDeviceUI);
  936. }
  937. void CDIDeviceActionConfigPage::OnClick(POINT point, WPARAM, BOOL bLeft)
  938. {
  939. if (!bLeft)
  940. return;
  941. // Unhighlight current callout
  942. ExitAssignState();
  943. if (m_pDeviceUI->GetNumViews() > 1)
  944. {
  945. int iCurView = m_pDeviceUI->GetCurViewIndex();
  946. if (PtInRect(&m_rectIBLeft, point))
  947. m_pDeviceUI->SetView(iCurView == 0 ? m_pDeviceUI->GetNumViews() - 1 : iCurView - 1);
  948. if (PtInRect(&m_rectIBRight, point))
  949. m_pDeviceUI->SetView(iCurView == m_pDeviceUI->GetNumViews() - 1 ? 0 : iCurView + 1);
  950. if (PtInRect(&m_rectIBText, point))
  951. DoViewSel();
  952. }
  953. }
  954. void CDIDeviceActionConfigPage::OnMouseOver(POINT point, WPARAM fwKeys)
  955. {
  956. CFlexWnd::s_ToolTip.SetEnable(FALSE);
  957. // Check view selection area so we can display text in info box.
  958. if (m_pDeviceUI->GetNumViews() > 1)
  959. {
  960. if (PtInRect(&m_rectIB, point))
  961. {
  962. SetInfoText(IDS_INFOMSG_VIEW_VIEWSEL);
  963. return;
  964. }
  965. }
  966. SetAppropriateDefaultText();
  967. }
  968. int GetActionIndexFromPointer(LPDIACTIONW p, LPDIACTIONFORMATW paf)
  969. {
  970. if (!p || !paf || !paf->rgoAction)
  971. return -1;
  972. int index = int((((LPBYTE)p) - ((LPBYTE)paf->rgoAction)) / (DWORD)sizeof(DIACTIONW));
  973. assert(&(paf->rgoAction[index]) == p);
  974. return index;
  975. }
  976. BOOL CDIDeviceActionConfigPage::IsActionAssignedHere(int index)
  977. {
  978. if (!m_lpDiac)
  979. return FALSE;
  980. if (index < 0 || index >= (int)m_lpDiac->dwNumActions)
  981. return FALSE;
  982. return IsEqualGUID(m_didi.guidInstance, m_lpDiac->rgoAction[index].guidInstance);
  983. }
  984. LRESULT CDIDeviceActionConfigPage::WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
  985. {
  986. switch (msg)
  987. {
  988. case WM_UNHIGHLIGHT:
  989. // Unhighlight current callout
  990. ExitAssignState();
  991. break;
  992. case WM_KEYDOWN:
  993. #ifdef DBG
  994. // In debug version, shift-escape exits the UI.
  995. if (wParam == VK_ESCAPE && GetAsyncKeyState(VK_SHIFT) < 0)
  996. {
  997. PostMessage(GetParent(m_hWnd), WM_KEYDOWN, wParam, lParam);
  998. break;
  999. }
  1000. #endif
  1001. // If this is a keyboard device, then click-to-pick will take care of the functionalities below.
  1002. // Process WM_KEYDOWN only for non-keyboard devices.
  1003. if (LOBYTE(m_didi.dwDevType) == DI8DEVTYPE_KEYBOARD) return 0;
  1004. switch(wParam)
  1005. {
  1006. case VK_RETURN:
  1007. // If we are not in assign state, enter it.
  1008. if (m_State == CFGSTATE_NORMAL && m_pCurControl)
  1009. EnterAssignState();
  1010. break;
  1011. case VK_DELETE:
  1012. // If we are in assign state and there is a control, unassign it.
  1013. if (m_State == CFGSTATE_ASSIGN && m_pCurControl)
  1014. UnassignCallout();
  1015. break;
  1016. case VK_ESCAPE:
  1017. if (m_State == CFGSTATE_ASSIGN)
  1018. ExitAssignState();
  1019. break;
  1020. }
  1021. return 0;
  1022. case WM_FLEXCHECKBOX:
  1023. switch(wParam)
  1024. {
  1025. case CHKNOTIFY_UNCHECK:
  1026. //@@BEGIN_MSINTERNAL
  1027. #ifdef DDKBUILD
  1028. if (!m_pDeviceUI->InEditMode()) // Ignore sort assigned checkbox if in DDK tool
  1029. {
  1030. #endif
  1031. //@@END_MSINTERNAL
  1032. m_pDeviceUI->GetCurView()->SortAssigned(FALSE);
  1033. if (m_pCurControl)
  1034. {
  1035. // Scroll so that we scroll to make this visible since it might be displaced by sorting.
  1036. m_pDeviceUI->GetCurView()->ScrollToMakeControlVisible(m_pCurControl->GetCalloutMaxRect());
  1037. }
  1038. Invalidate();
  1039. //@@BEGIN_MSINTERNAL
  1040. #ifdef DDKBUILD
  1041. }
  1042. #endif
  1043. //@@END_MSINTERNAL
  1044. break;
  1045. case CHKNOTIFY_CHECK:
  1046. //@@BEGIN_MSINTERNAL
  1047. #ifdef DDKBUILD
  1048. if (!m_pDeviceUI->InEditMode()) // Ignore sort assigned checkbox if in DDK tool
  1049. {
  1050. #endif
  1051. //@@END_MSINTERNAL
  1052. m_pDeviceUI->GetCurView()->SortAssigned(TRUE);
  1053. if (m_pCurControl)
  1054. {
  1055. // Scroll so that we scroll to make this visible since it might be displaced by sorting.
  1056. m_pDeviceUI->GetCurView()->ScrollToMakeControlVisible(m_pCurControl->GetCalloutMaxRect());
  1057. }
  1058. Invalidate();
  1059. //@@BEGIN_MSINTERNAL
  1060. #ifdef DDKBUILD
  1061. }
  1062. #endif
  1063. //@@END_MSINTERNAL
  1064. break;
  1065. case CHKNOTIFY_MOUSEOVER:
  1066. SetInfoText(m_CheckBox.GetCheck() ? IDS_INFOMSG_VIEW_SORTENABLED : IDS_INFOMSG_VIEW_SORTDISABLED);
  1067. break;
  1068. }
  1069. break;
  1070. case WM_FLEXCOMBOBOX:
  1071. switch (wParam)
  1072. {
  1073. case FCBN_MOUSEOVER:
  1074. if (lParam)
  1075. {
  1076. CFlexComboBox *pCombo = (CFlexComboBox*)lParam;
  1077. if (pCombo->m_hWnd == m_UserNames.m_hWnd)
  1078. SetInfoText(m_puig->InEditMode() ? IDS_INFOMSG_EDIT_USERNAME : IDS_INFOMSG_VIEW_USERNAME);
  1079. else if (pCombo->m_hWnd == m_Genres.m_hWnd)
  1080. SetInfoText(m_puig->InEditMode() ? IDS_INFOMSG_EDIT_GAMEMODE : IDS_INFOMSG_VIEW_GAMEMODE);
  1081. }
  1082. break;
  1083. case FCBN_SELCHANGE:
  1084. // Clear the tool tip as the combo-box has closed
  1085. CFlexWnd::s_ToolTip.SetEnable(FALSE);
  1086. CFlexWnd::s_ToolTip.SetToolTipParent(NULL);
  1087. if (m_pUIFrame && m_puig)
  1088. {
  1089. ExitAssignState();
  1090. m_pUIFrame->SetCurGenre(m_Genres.GetSel());
  1091. int nUser = m_UserNames.GetSel();
  1092. if (m_puig->GetNumUserNames() > 0 && nUser >= m_puig->GetNumUserNames())
  1093. nUser = -1;
  1094. m_pUIFrame->SetCurUser(m_nPageIndex, nUser);
  1095. }
  1096. break;
  1097. }
  1098. return 0;
  1099. case WM_FLEXTREENOTIFY:
  1100. {
  1101. // Check if this is a mouse over message (just for info box update)
  1102. if (wParam == FTN_MOUSEOVER)
  1103. {
  1104. SetAppropriateDefaultText();
  1105. return FALSE;
  1106. }
  1107. if (!lParam)
  1108. return FALSE;
  1109. FLEXTREENOTIFY &n = *((FLEXTREENOTIFY *)(LPVOID)lParam);
  1110. if (!n.pItem)
  1111. return FALSE;
  1112. switch (wParam)
  1113. {
  1114. case FTN_OWNERDRAW:
  1115. {
  1116. POINT ofs = {0, 0};
  1117. CBitmap *pbmGlyph = NULL;
  1118. BOOL bAssigned = FALSE, bAssignedHere = FALSE;
  1119. if (n.pItem->IsUserGUID(GUID_ActionItem))
  1120. {
  1121. LPDIACTIONW lpac = GetItemLpac(n.pItem, 0);
  1122. if (lpac)
  1123. // We now walk through each DIACTION and find those with action name match, then see if
  1124. // they are assigned anywhere.
  1125. for (DWORD i = 0; i < m_lpDiac->dwNumActions; ++i)
  1126. {
  1127. if (wcscmp(lpac->lptszActionName, m_lpDiac->rgoAction[i].lptszActionName))
  1128. continue;
  1129. if (bAssignedHere = IsActionAssignedHere(i))
  1130. {
  1131. bAssigned = TRUE;
  1132. break;
  1133. }
  1134. if (m_pUIFrame && m_pUIFrame->QueryActionAssignedAnywhere(m_didi.guidInstance, i) == S_OK)
  1135. bAssigned = TRUE;
  1136. }
  1137. if (bAssigned || bAssignedHere)
  1138. {
  1139. pbmGlyph = bAssignedHere ? m_pbmCheckGlyph :
  1140. m_pbmCheckGlyphDark;
  1141. pbmGlyph->FigureSize();
  1142. ofs.x = 2;
  1143. ofs.y = 4;
  1144. }
  1145. }
  1146. else
  1147. {
  1148. if (n.pItem == m_pRelAxesParent)
  1149. pbmGlyph = m_pbmRelAxesGlyph;
  1150. if (n.pItem == m_pAbsAxesParent)
  1151. pbmGlyph = m_pbmAbsAxesGlyph;
  1152. if (n.pItem == m_pButtonParent)
  1153. pbmGlyph = m_pbmButtonGlyph;
  1154. if (n.pItem == m_pHatParent)
  1155. pbmGlyph = m_pbmHatGlyph;
  1156. ofs.y = 2;
  1157. }
  1158. if (!pbmGlyph)
  1159. return FALSE;
  1160. n.pItem->PaintInto(n.hDC);
  1161. RECT rect;
  1162. CPaintHelper ph(*m_puig, n.hDC);
  1163. ph.SetElement(UIE_GLYPH);
  1164. n.pItem->GetMargin(rect);
  1165. pbmGlyph->Draw(n.hDC, ofs.x, rect.top + ofs.y);
  1166. return TRUE;
  1167. }
  1168. case FTN_CLICK:
  1169. // We cannot assign a different control to this action if it has the DIA_APPFIXED flag.
  1170. if (n.pItem->IsUserGUID(GUID_ActionItem) && GetItemLpac(n.pItem) && !(GetItemLpac(n.pItem)->dwFlags & DIA_APPFIXED))
  1171. {
  1172. m_Tree.SetCurSel(n.pItem);
  1173. ActionClick(GetItemLpac(n.pItem));
  1174. }
  1175. else
  1176. {
  1177. #ifdef CFGUI__ALLOW_USER_ACTION_TREE_BRANCH_MANIPULATION
  1178. if (!n.pItem->IsExpanded())
  1179. n.pItem->Expand();
  1180. else
  1181. n.pItem->Collapse();
  1182. #endif
  1183. }
  1184. break;
  1185. }
  1186. break;
  1187. }
  1188. }
  1189. return CFlexWnd::WndProc(hWnd, msg, wParam, lParam);
  1190. }
  1191. void CDIDeviceActionConfigPage::SetInvalid(LPDIACTIONW lpac)
  1192. {
  1193. lpac->guidInstance = GUID_NULL;
  1194. lpac->dwObjID = (DWORD)-1;
  1195. }
  1196. DWORD CDIDeviceActionConfigPage::GetOffset(LPDIACTIONW lpac)
  1197. {
  1198. return lpac ? lpac->dwObjID : (DWORD)-1;
  1199. }
  1200. void CDIDeviceActionConfigPage::SetOffset(LPDIACTIONW lpac, DWORD ofs)
  1201. {
  1202. assert(lpac != NULL);
  1203. if (!lpac)
  1204. return;
  1205. lpac->dwObjID = ofs;
  1206. }
  1207. HRESULT CDIDeviceActionConfigPage::InitLookup()
  1208. {
  1209. DIDEVOBJSTRUCT os;
  1210. HRESULT hresult = FillDIDeviceObjectStruct(os, m_lpDID);
  1211. if (FAILED(hresult))
  1212. return hresult;
  1213. for (int i = 0; i < os.nObjects; i++)
  1214. {
  1215. DIDEVICEOBJECTINSTANCEW &doi = os.pdoi[i];
  1216. offset_objid.add(doi.dwOfs, doi.dwType);
  1217. }
  1218. return S_OK;
  1219. }
  1220. HRESULT CDIDeviceActionConfigPage::SetEditLayout(BOOL bEditLayout)
  1221. {
  1222. m_pDeviceUI->SetEditMode(bEditLayout);
  1223. return S_OK;
  1224. }
  1225. //@@BEGIN_MSINTERNAL
  1226. #ifdef DDKBUILD
  1227. HRESULT CDIDeviceActionConfigPage::WriteIHVSetting()
  1228. {
  1229. m_pDeviceUI->WriteToINI();
  1230. return S_OK;
  1231. }
  1232. #endif
  1233. //@@END_MSINTERNAL
  1234. BOOL CDIDeviceActionConfigPage::IsControlMapped(CDeviceControl *pControl)
  1235. {
  1236. if (pControl == NULL)
  1237. return FALSE;
  1238. if (!pControl->IsOffsetAssigned())
  1239. return FALSE;
  1240. if (m_lpDiac == NULL)
  1241. return FALSE;
  1242. for (DWORD i = 0; i < m_lpDiac->dwNumActions; i++)
  1243. if (GetOffset(&(m_lpDiac->rgoAction[i])) == pControl->GetOffset())
  1244. return TRUE;
  1245. return FALSE;
  1246. }
  1247. void CDIDeviceActionConfigPage::InitDevice()
  1248. {
  1249. if (m_lpDID == NULL || m_pDeviceUI == NULL || m_pUIFrame == NULL)
  1250. return;
  1251. HWND hWndMain = m_pUIFrame->GetMainHWND();
  1252. if (!hWndMain)
  1253. return;
  1254. // don't do anything if this is a mouse
  1255. switch ((DWORD)(LOBYTE(LOWORD(m_pDeviceUI->m_didi.dwDevType))))
  1256. {
  1257. case DI8DEVTYPE_MOUSE:
  1258. return;
  1259. }
  1260. // init/prepare...
  1261. int i;
  1262. const DIDEVOBJSTRUCT &os = m_pDeviceUI->m_os;
  1263. int nObjects = os.nObjects;
  1264. DIDATAFORMAT df;
  1265. df.dwSize = sizeof(DIDATAFORMAT);
  1266. df.dwObjSize = sizeof(DIOBJECTDATAFORMAT);
  1267. df.dwFlags = DIDF_ABSAXIS;
  1268. df.dwDataSize = sizeof(DWORD) * (DWORD)nObjects;
  1269. df.dwNumObjs = (DWORD)nObjects;
  1270. df.rgodf = (DIOBJECTDATAFORMAT *)malloc(sizeof(DIOBJECTDATAFORMAT) * nObjects);
  1271. if (df.rgodf == NULL)
  1272. {
  1273. etrace1(_T("Could not allocate DIOBJECTDATAFORMAT array of %d elements\n"), nObjects);
  1274. return;
  1275. }
  1276. m_cbDeviceDataSize = df.dwDataSize;
  1277. for (int c = 0; c < 2; c++)
  1278. {
  1279. if (m_pDeviceData[c] != NULL)
  1280. free(m_pDeviceData[c]);
  1281. m_pDeviceData[c] = (DWORD *)malloc(m_cbDeviceDataSize);
  1282. if (m_pDeviceData[c] == NULL)
  1283. etrace2(_T("Could not allocate device data buffer %d of %d bytes\n"), c, m_cbDeviceDataSize);
  1284. }
  1285. m_nOnDeviceData = 0;
  1286. m_bFirstDeviceData = TRUE;
  1287. for (i = 0; i < nObjects; i++)
  1288. {
  1289. DIOBJECTDATAFORMAT *podf = &(df.rgodf[i]);
  1290. podf->pguid = NULL;
  1291. podf->dwOfs = i * sizeof(DWORD);
  1292. podf->dwType = os.pdoi[i].dwType;
  1293. podf->dwFlags = 0;
  1294. }
  1295. if (df.rgodf != NULL)
  1296. {
  1297. HRESULT hr = m_lpDID->SetDataFormat(&df);
  1298. free(df.rgodf);
  1299. df.rgodf = NULL;
  1300. if (FAILED(hr))
  1301. {
  1302. etrace1(_T("SetDataFormat() failed, returning 0x%08x\n"), hr);
  1303. }
  1304. else
  1305. {
  1306. hr = m_lpDID->SetCooperativeLevel(hWndMain, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE);
  1307. if (FAILED(hr))
  1308. etrace1(_T("SetCooperativeLevel() failed, returning 0x%08x\n"), hr);
  1309. DIPROPRANGE range;
  1310. range.diph.dwSize = sizeof(DIPROPRANGE);
  1311. range.diph.dwHeaderSize = sizeof(DIPROPHEADER);
  1312. range.diph.dwObj = 0;
  1313. range.diph.dwHow = DIPH_DEVICE;
  1314. range.lMin = DEVICE_POLLING_AXIS_MIN;
  1315. range.lMax = DEVICE_POLLING_AXIS_MAX;
  1316. hr = m_lpDID->SetProperty(DIPROP_RANGE, (LPCDIPROPHEADER)&range);
  1317. if (FAILED(hr))
  1318. etrace1(_T("SetProperty(DIPROP_RANGE, ...) failed, returning 0x%08x\n"), hr);
  1319. hr = m_lpDID->Acquire();
  1320. if (FAILED(hr))
  1321. etrace1(_T("Acquire() failed, returning 0x%08x\n"), hr);
  1322. }
  1323. }
  1324. }
  1325. void CALLBACK CDIDeviceActionConfigPage::DeviceTimerProc(UINT uID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2)
  1326. {
  1327. if (!IsWindow((HWND)dwUser)) return; // Verify that dwUser is a valid window handle
  1328. CDIDeviceActionConfigPage *pPage = (CDIDeviceActionConfigPage *)GetFlexWnd((HWND)dwUser); // Get flex object
  1329. if (pPage)
  1330. pPage->DeviceTimer();
  1331. }
  1332. void CDIDeviceActionConfigPage::DeviceTimer()
  1333. {
  1334. DWORD *pOldData = m_pDeviceData[m_nOnDeviceData];
  1335. m_nOnDeviceData = (m_nOnDeviceData + 1) & 1;
  1336. DWORD *pData = m_pDeviceData[m_nOnDeviceData];
  1337. if (m_lpDID == NULL || pData == NULL || pOldData == NULL)
  1338. {
  1339. // Required data not available. Return and there'll be no more timer callbacks.
  1340. etrace(_T("DeviceTimer() failed\n"));
  1341. return;
  1342. }
  1343. // Get device data only if this page is visible.
  1344. if (m_lpDiac)
  1345. {
  1346. HRESULT hr = m_lpDID->Poll();
  1347. if (SUCCEEDED(hr))
  1348. {
  1349. hr = m_lpDID->GetDeviceState(m_cbDeviceDataSize, pData);
  1350. if (SUCCEEDED(hr))
  1351. {
  1352. if (!m_bFirstDeviceData)
  1353. {
  1354. DeviceDelta(pData, pOldData);
  1355. } else
  1356. {
  1357. m_bFirstDeviceData = FALSE;
  1358. }
  1359. } else
  1360. {
  1361. etrace1(_T("GetDeviceState() failed, returning 0x%08x\n"), hr);
  1362. }
  1363. } else
  1364. {
  1365. etrace1(_T("Poll() failed, returning 0x%08x\n"), hr);
  1366. }
  1367. }
  1368. // Set the next timer event.
  1369. if (g_fptimeSetEvent)
  1370. g_fptimeSetEvent(DEVICE_POLLING_INTERVAL, DEVICE_POLLING_INTERVAL,
  1371. CDIDeviceActionConfigPage::DeviceTimerProc, (DWORD_PTR)m_hWnd, TIME_ONESHOT);
  1372. }
  1373. void CDIDeviceActionConfigPage::DeviceDelta(DWORD *pData, DWORD *pOldData)
  1374. {
  1375. if (pData == NULL || pOldData == NULL || m_pDeviceUI == NULL)
  1376. return;
  1377. const DIDEVOBJSTRUCT &os = m_pDeviceUI->m_os;
  1378. // see which objects changed
  1379. for (int i = 0; i < os.nObjects; i++)
  1380. {
  1381. // for axes, we need to do special processing
  1382. if (os.pdoi[i].dwType & DIDFT_AXIS)
  1383. {
  1384. BOOL bSig = FALSE, bOldSig = FALSE;
  1385. StoreAxisDeltaAndCalcSignificance(os.pdoi[i],
  1386. pData[i], pOldData[i], bSig, bOldSig);
  1387. AxisDelta(os.pdoi[i], bSig, bOldSig);
  1388. continue;
  1389. }
  1390. // for all others, skip that which didn't change
  1391. if (pData[i] == pOldData[i])
  1392. continue;
  1393. // pass to appropriate delta function
  1394. DWORD dwObjId = os.pdoi[i].dwType;
  1395. if (dwObjId & DIDFT_BUTTON)
  1396. ButtonDelta(os.pdoi[i], pData[i], pOldData[i]);
  1397. else if (dwObjId & DIDFT_POV)
  1398. PovDelta(os.pdoi[i], pData[i], pOldData[i]);
  1399. }
  1400. }
  1401. void CDIDeviceActionConfigPage::StoreAxisDeltaAndCalcSignificance(const DIDEVICEOBJECTINSTANCEW &doi, DWORD data, DWORD olddata, BOOL &bSig, BOOL &bOldSig)
  1402. {
  1403. // see if this object has an axis value array
  1404. int i;
  1405. if (objid_avai.getright(doi.dwType, i))
  1406. {
  1407. AxisValueArray &ar = m_AxisValueArray[i];
  1408. int on = ar[0] + 1;
  1409. if (on >= ar.GetSize())
  1410. on = DEVICE_POLLING_ACBUF_START_INDEX;
  1411. ar[0] = on;
  1412. int delta = abs(int(data) - int(olddata));
  1413. // Scale up the delta if this is a wheel axis as wheels are harder to move generally.
  1414. if (LOBYTE(m_didi.dwDevType) == DI8DEVTYPE_DRIVING && doi.guidType == GUID_XAxis)
  1415. delta = delta * DEVICE_POLLING_WHEEL_SCALE_FACTOR;
  1416. if (delta < DEVICE_POLLING_AXIS_MINDELTA)
  1417. delta = 0;
  1418. int cumul = ar[1]; // Retrieve cumulative value for easier processing
  1419. cumul -= ar[on]; // Subtract value in current slot from cumul since it's being thrown away.
  1420. cumul += delta; // Add current delta to cumul
  1421. ar[on] = delta; // Store the delta at current slot
  1422. ar[1] = cumul; // Save cumulative value
  1423. bOldSig = (BOOL)ar[2];
  1424. ar[2] = int(bSig = cumul > DEVICE_POLLING_AXIS_SIGNIFICANT);
  1425. if (bSig)
  1426. {
  1427. // This axis is about to be activated. We now reset the history and cumulative movement since we don't need them any more.
  1428. ar[0] = DEVICE_POLLING_ACBUF_START_INDEX;
  1429. ar[1] = 0;
  1430. ar[2] = FALSE;
  1431. for (int c = DEVICE_POLLING_ACBUF_START_INDEX;
  1432. c < DEVICE_POLLING_ACBUF_START_INDEX + DEVICE_POLLING_AXIS_ACCUMULATION; c++)
  1433. ar[c] = 0;
  1434. }
  1435. }
  1436. else
  1437. {
  1438. i = m_AxisValueArray.GetSize();
  1439. m_AxisValueArray.SetSize(i + 1);
  1440. objid_avai.add(doi.dwType, i);
  1441. AxisValueArray &ar = m_AxisValueArray[i];
  1442. ar.SetSize(DEVICE_POLLING_ACBUF_START_INDEX + DEVICE_POLLING_AXIS_ACCUMULATION);
  1443. ar[0] = DEVICE_POLLING_ACBUF_START_INDEX;
  1444. ar[1] = 0;
  1445. ar[2] = FALSE;
  1446. for (int c = DEVICE_POLLING_ACBUF_START_INDEX;
  1447. c < DEVICE_POLLING_ACBUF_START_INDEX + DEVICE_POLLING_AXIS_ACCUMULATION; c++)
  1448. ar[c] = 0;
  1449. bOldSig = bSig = FALSE;
  1450. }
  1451. }
  1452. void CDIDeviceActionConfigPage::AxisDelta(const DIDEVICEOBJECTINSTANCEW &doi, BOOL data, BOOL old)
  1453. {
  1454. if (data && !old)
  1455. {
  1456. if (m_State == CFGSTATE_NORMAL)
  1457. ActivateObject(doi);
  1458. }
  1459. if (old && !data)
  1460. DeactivateObject(doi);
  1461. }
  1462. void CDIDeviceActionConfigPage::ButtonDelta(const DIDEVICEOBJECTINSTANCEW &doi, DWORD data, DWORD old)
  1463. {
  1464. static DWORD dwLastOfs;
  1465. static DWORD dwLastTimeStamp;
  1466. if (data && !old)
  1467. {
  1468. // Do special processing for keyboard
  1469. if (LOBYTE(m_didi.dwDevType) == DI8DEVTYPE_KEYBOARD)
  1470. {
  1471. // If this is an ENTER key, we enter the assign state if not already in it.
  1472. if (doi.dwOfs == DIK_RETURN || doi.dwOfs == DIK_NUMPADENTER)
  1473. {
  1474. if (m_State == CFGSTATE_NORMAL && m_pCurControl)
  1475. EnterAssignState();
  1476. return; // Do nothing other than entering the assign state. No highlighting
  1477. }
  1478. // DELETE key case
  1479. // If we are in assign state and there is a control, unassign it.
  1480. if (doi.dwOfs == DIK_DELETE && m_State == CFGSTATE_ASSIGN && m_pCurControl)
  1481. {
  1482. UnassignCallout();
  1483. return; // Don't highlight or do pick to click for delete if this press happens during assign state.
  1484. }
  1485. // ESCAPE key case
  1486. if (doi.dwOfs == DIK_ESCAPE && m_State == CFGSTATE_ASSIGN)
  1487. {
  1488. ExitAssignState();
  1489. return;
  1490. }
  1491. // For all other keys, still process click-to-pick or highlighting.
  1492. }
  1493. // Enter assign state if this is a double activation
  1494. if (m_State == CFGSTATE_NORMAL)
  1495. {
  1496. ActivateObject(doi);
  1497. if (doi.dwOfs == dwLastOfs && dwLastTimeStamp + GetDoubleClickTime() > GetTickCount())
  1498. {
  1499. // We check if a callout for this control exists. If not, do not enter assign state.
  1500. CDeviceView *pCurView = m_pDeviceUI->GetCurView();
  1501. CDeviceControl *pControl = pCurView->GetControlFromOfs(doi.dwType);
  1502. if (pControl)
  1503. EnterAssignState();
  1504. }
  1505. dwLastOfs = doi.dwOfs;
  1506. dwLastTimeStamp = GetTickCount();
  1507. }
  1508. }
  1509. if (old && !data)
  1510. DeactivateObject(doi);
  1511. }
  1512. void CDIDeviceActionConfigPage::PovDelta(const DIDEVICEOBJECTINSTANCEW &doi, DWORD data, DWORD old)
  1513. {
  1514. BOOL d = data != -1, o = old != -1;
  1515. if (d && !o)
  1516. {
  1517. if (m_State == CFGSTATE_NORMAL)
  1518. ActivateObject(doi);
  1519. }
  1520. if (o && !d)
  1521. DeactivateObject(doi);
  1522. }
  1523. void CDIDeviceActionConfigPage::ActivateObject(const DIDEVICEOBJECTINSTANCEW &doi)
  1524. {
  1525. if (m_pDeviceUI == NULL)
  1526. return;
  1527. //@@BEGIN_MSINTERNAL
  1528. #ifdef DDKBUILD
  1529. if (m_pDeviceUI->GetCurView()->InEditState())
  1530. return;
  1531. #endif
  1532. //@@END_MSINTERNAL
  1533. CDeviceView *pCurView = m_pDeviceUI->GetCurView(), *pView = pCurView;
  1534. if (pView == NULL)
  1535. return;
  1536. CDeviceControl *pControl = pView->GetControlFromOfs(doi.dwType);
  1537. if (pControl == NULL)
  1538. {
  1539. for (int i = 0; i < m_pDeviceUI->GetNumViews(); i++)
  1540. {
  1541. pView = m_pDeviceUI->GetView(i);
  1542. if (pView == NULL)
  1543. continue;
  1544. pControl = pView->GetControlFromOfs(doi.dwType);
  1545. if (pControl != NULL)
  1546. break;
  1547. }
  1548. if (pControl != NULL && pView != NULL && pView != pCurView)
  1549. {
  1550. // switch to view
  1551. m_pDeviceUI->SetView(pView);
  1552. SetControlAssignments();
  1553. SetCurrentControl(NULL);
  1554. }
  1555. }
  1556. if (pControl != NULL)
  1557. SetCurrentControl(pControl);
  1558. SetAppropriateDefaultText();
  1559. }
  1560. void CDIDeviceActionConfigPage::DeactivateObject(const DIDEVICEOBJECTINSTANCEW &doi)
  1561. {
  1562. // Add code that needs to be run when deactivating here.
  1563. }
  1564. HRESULT CDIDeviceActionConfigPage::Unacquire()
  1565. {
  1566. if (m_lpDID != NULL)
  1567. m_lpDID->Unacquire();
  1568. return S_OK;
  1569. }
  1570. HRESULT CDIDeviceActionConfigPage::Reacquire()
  1571. {
  1572. InitDevice();
  1573. return S_OK;
  1574. }
  1575. void CDIDeviceActionConfigPage::EnterAssignState()
  1576. {
  1577. if (!m_puig->InEditMode())
  1578. return;
  1579. if (!m_pCurControl || m_pCurControl->IsFixed())
  1580. return;
  1581. SetInfoText(IDS_INFOMSG_EDIT_EDITMODEENABLED);
  1582. m_State = CFGSTATE_ASSIGN; // Into the assign state.
  1583. ShowCurrentControlAssignment(); // Show the tree
  1584. m_Tree.Invalidate();
  1585. Invalidate();
  1586. }
  1587. void CDIDeviceActionConfigPage::ExitAssignState()
  1588. {
  1589. m_State = CFGSTATE_NORMAL; // Out of the assign state.
  1590. SetCurrentControl(NULL); // Unselect the control
  1591. ShowCurrentControlAssignment(); // Show the tree
  1592. m_Tree.Invalidate();
  1593. Invalidate();
  1594. SetAppropriateDefaultText();
  1595. }
  1596. HRESULT CDIDeviceActionConfigPage::SetInfoText(int iCode)
  1597. {
  1598. // We check for special code -1 here. This is only called by CConfigWnd, and means that we should
  1599. // call SetAppropriateDefaultText to display proper text.
  1600. if (iCode == -1)
  1601. SetAppropriateDefaultText();
  1602. else
  1603. m_InfoBox.SetText(iCode);
  1604. return S_OK;
  1605. }
  1606. void CDIDeviceActionConfigPage::SetAppropriateDefaultText()
  1607. {
  1608. if (m_puig->InEditMode())
  1609. {
  1610. if (m_State == CFGSTATE_ASSIGN)
  1611. SetInfoText(IDS_INFOMSG_EDIT_EDITMODEENABLED);
  1612. else if (m_pCurControl)
  1613. {
  1614. if (m_pCurControl->IsFixed())
  1615. SetInfoText(IDS_INFOMSG_APPFIXEDSELECT);
  1616. else
  1617. SetInfoText(IDS_INFOMSG_EDIT_CTRLSELECTED);
  1618. }
  1619. else
  1620. {
  1621. if (LOBYTE(m_didi.dwDevType) == DI8DEVTYPE_KEYBOARD)
  1622. SetInfoText(IDS_INFOMSG_EDIT_KEYBOARD);
  1623. else
  1624. if (LOBYTE(m_didi.dwDevType) == DI8DEVTYPE_MOUSE)
  1625. SetInfoText(IDS_INFOMSG_EDIT_MOUSE);
  1626. else
  1627. SetInfoText(IDS_INFOMSG_EDIT_DEVICE);
  1628. }
  1629. } else
  1630. SetInfoText(IDS_INFOMSG_VIEW_DEVICE);
  1631. }