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.

343 lines
8.1 KiB

  1. //-----------------------------------------------------------------------------
  2. // File: usefuldi.cpp
  3. //
  4. // Desc: Contains various DInput-specific utility classes and functions
  5. // to help the UI carry its operations more easily.
  6. //
  7. // Copyright (C) 1999-2000 Microsoft Corporation. All Rights Reserved.
  8. //-----------------------------------------------------------------------------
  9. #include "common.hpp"
  10. // don't want useful.cpp to use precompiled header
  11. #include "useful.cpp"
  12. BOOL IsObjectOnExcludeList(DWORD dwOfs)
  13. {
  14. if (dwOfs == DIK_PREVTRACK ||
  15. dwOfs == DIK_NEXTTRACK ||
  16. dwOfs == DIK_MUTE ||
  17. dwOfs == DIK_CALCULATOR ||
  18. dwOfs == DIK_PLAYPAUSE ||
  19. dwOfs == DIK_MEDIASTOP ||
  20. dwOfs == DIK_VOLUMEDOWN ||
  21. dwOfs == DIK_VOLUMEUP ||
  22. dwOfs == DIK_WEBHOME ||
  23. dwOfs == DIK_SLEEP ||
  24. dwOfs == DIK_WEBSEARCH ||
  25. dwOfs == DIK_WEBFAVORITES ||
  26. dwOfs == DIK_WEBREFRESH ||
  27. dwOfs == DIK_WEBSTOP ||
  28. dwOfs == DIK_WEBFORWARD ||
  29. dwOfs == DIK_WEBBACK ||
  30. dwOfs == DIK_MYCOMPUTER ||
  31. dwOfs == DIK_MAIL ||
  32. dwOfs == DIK_MEDIASELECT ||
  33. dwOfs == DIK_LWIN ||
  34. dwOfs == DIK_RWIN ||
  35. dwOfs == DIK_POWER ||
  36. dwOfs == DIK_WAKE)
  37. return TRUE;
  38. return FALSE;
  39. }
  40. BOOL CALLBACK IncrementValPerObject(LPCDIDEVICEOBJECTINSTANCEW lpddoi, LPVOID pvRef)
  41. {
  42. if (pvRef != NULL)
  43. ++(*((int *)pvRef));
  44. return DIENUM_CONTINUE;
  45. }
  46. BOOL CALLBACK KeyboardIncrementValPerObject(LPCDIDEVICEOBJECTINSTANCEW lpddoi, LPVOID pvRef)
  47. {
  48. if (pvRef != NULL && !IsObjectOnExcludeList(lpddoi->dwOfs))
  49. ++(*((int *)pvRef));
  50. return DIENUM_CONTINUE;
  51. }
  52. BOOL CALLBACK FillDIDeviceObject(LPCDIDEVICEOBJECTINSTANCEW lpddoi, LPVOID pvRef)
  53. {
  54. if (pvRef == NULL || lpddoi == NULL)
  55. return DIENUM_CONTINUE;
  56. DIDEVOBJSTRUCT &os = *((DIDEVOBJSTRUCT *)pvRef);
  57. assert(os.pdoi != NULL);
  58. assert(os.n < os.nObjects);
  59. if (os.pdoi != NULL && os.n < os.nObjects)
  60. os.pdoi[os.n++] = *lpddoi;
  61. return DIENUM_CONTINUE;
  62. }
  63. // This is a special EnumObjects() callback for keyboard type devices. When we enumerate, dwOfs
  64. // member of lpddoi is meaningless. We need to take the middle 16 bits of dwType as dwOfs
  65. // (also same as DIK_xxx).
  66. BOOL CALLBACK FillDIKeyboardDeviceObject(LPCDIDEVICEOBJECTINSTANCEW lpddoi, LPVOID pvRef)
  67. {
  68. if (pvRef == NULL || lpddoi == NULL || IsObjectOnExcludeList(lpddoi->dwOfs))
  69. return DIENUM_CONTINUE;
  70. DIDEVOBJSTRUCT &os = *((DIDEVOBJSTRUCT *)pvRef);
  71. assert(os.pdoi != NULL);
  72. assert(os.n < os.nObjects);
  73. if (os.pdoi != NULL && os.n < os.nObjects)
  74. {
  75. os.pdoi[os.n] = *lpddoi;
  76. os.pdoi[os.n].dwOfs = os.pdoi[os.n].dwType >> 8;
  77. wcscpy(os.pdoi[os.n].tszName, lpddoi->tszName);
  78. ++os.n;
  79. }
  80. return DIENUM_CONTINUE;
  81. }
  82. HRESULT FillDIDeviceObjectStruct(DIDEVOBJSTRUCT &os, LPDIRECTINPUTDEVICE8W pDID)
  83. {
  84. if (pDID == NULL)
  85. return E_FAIL;
  86. DIDEVICEINSTANCEW didi;
  87. didi.dwSize = sizeof(didi);
  88. pDID->GetDeviceInfo(&didi);
  89. HRESULT hr;
  90. if (LOBYTE(didi.dwDevType) == DI8DEVTYPE_KEYBOARD)
  91. hr = pDID->EnumObjects(KeyboardIncrementValPerObject, &os.nObjects,
  92. DIDFT_AXIS | DIDFT_BUTTON | DIDFT_POV);
  93. else
  94. hr = pDID->EnumObjects(IncrementValPerObject, &os.nObjects,
  95. DIDFT_AXIS | DIDFT_BUTTON | DIDFT_POV);
  96. if (FAILED(hr))
  97. {
  98. os.nObjects = 0;
  99. return hr;
  100. }
  101. if (os.nObjects == 0)
  102. return S_OK;
  103. if (os.pdoi != NULL)
  104. free(os.pdoi);
  105. os.pdoi = (DIDEVICEOBJECTINSTANCEW *)malloc(sizeof(DIDEVICEOBJECTINSTANCEW) * os.nObjects);
  106. if (os.pdoi == NULL)
  107. {
  108. os.nObjects = 0;
  109. return E_FAIL;
  110. }
  111. // Check if this device is a keyboard. If so, it needs special treatment.
  112. os.n = 0;
  113. if ((didi.dwDevType & 0xFF) == DI8DEVTYPE_KEYBOARD)
  114. {
  115. hr = pDID->EnumObjects(FillDIKeyboardDeviceObject, &os,
  116. DIDFT_AXIS | DIDFT_BUTTON | DIDFT_POV);
  117. } else {
  118. hr = pDID->EnumObjects(FillDIDeviceObject, &os,
  119. DIDFT_AXIS | DIDFT_BUTTON | DIDFT_POV);
  120. }
  121. if (FAILED(hr))
  122. {
  123. os.nObjects = 0;
  124. return hr;
  125. }
  126. assert(os.nObjects == os.n);
  127. os.nObjects = os.n;
  128. return S_OK;
  129. }
  130. LPTSTR AllocConfigureFlagStr(DWORD dwFlags)
  131. {
  132. static const AFS_FLAG flag[] = {
  133. #define f(F) { F, _T(#F) }
  134. f(DICD_EDIT), f(DICD_DEFAULT)
  135. #undef f
  136. };
  137. static const int flags = sizeof(flag) / sizeof(AFS_FLAG);
  138. return AllocFlagStr(dwFlags, flag, flags);
  139. }
  140. LPTSTR AllocActionFlagStr(DWORD dwFlags)
  141. {
  142. static const AFS_FLAG flag[] = {
  143. #define f(F) { F, _T(#F) }
  144. f(DIA_FORCEFEEDBACK),
  145. f(DIA_APPMAPPED),
  146. f(DIA_APPNOMAP),
  147. f(DIA_NORANGE),
  148. #undef f
  149. }; static const int flags = sizeof(flag) / sizeof(AFS_FLAG);
  150. return AllocFlagStr(dwFlags, flag, flags);
  151. }
  152. LPTSTR AllocActionHowFlagStr(DWORD dwFlags)
  153. {
  154. static const AFS_FLAG flag[] = {
  155. #define f(F) { F, _T(#F) }
  156. f(DIAH_UNMAPPED),
  157. f(DIAH_USERCONFIG),
  158. f(DIAH_APPREQUESTED),
  159. f(DIAH_HWAPP),
  160. f(DIAH_HWDEFAULT),
  161. f(DIAH_DEFAULT),
  162. f(DIAH_ERROR)
  163. #undef f
  164. }; static const int flags = sizeof(flag) / sizeof(AFS_FLAG);
  165. return AllocFlagStr(dwFlags, flag, flags);
  166. }
  167. void CleanupActionFormatCopy(DIACTIONFORMATW &c)
  168. {
  169. if (c.rgoAction != NULL)
  170. {
  171. for (DWORD i = 0; i < c.dwNumActions; i++)
  172. if (c.rgoAction[i].lptszActionName != NULL)
  173. free((LPTSTR)c.rgoAction[i].lptszActionName);
  174. free(c.rgoAction);
  175. }
  176. c.rgoAction = NULL;
  177. }
  178. HRESULT CopyActionFormat(DIACTIONFORMATW &to, const DIACTIONFORMATW &from)
  179. {
  180. DWORD i;
  181. // copy all simple members
  182. to = from;
  183. // null copied pointers since we're going to duplicate them (makes sure cleanup works)
  184. to.rgoAction = NULL;
  185. // handle pointers/arrays/strings
  186. to.rgoAction = new DIACTIONW [to.dwNumActions];
  187. if (to.rgoAction == NULL)
  188. goto fail;
  189. // first null it all
  190. memset(to.rgoAction, 0, sizeof(DIACTIONW) * to.dwNumActions);
  191. // now copy...
  192. for (i = 0; i < to.dwNumActions; i++)
  193. {
  194. // copy simple members
  195. to.rgoAction[i] = from.rgoAction[i];
  196. // handle pointers/arrays/strings
  197. to.rgoAction[i].lptszActionName = _wcsdup(from.rgoAction[i].lptszActionName);
  198. if (to.rgoAction[i].lptszActionName == NULL)
  199. goto fail;
  200. }
  201. return S_OK;
  202. fail:
  203. CleanupActionFormatCopy(to);
  204. return E_OUTOFMEMORY;
  205. }
  206. LPDIACTIONFORMATW DupActionFormat(LPCDIACTIONFORMATW lpAcFor)
  207. {
  208. if (!lpAcFor)
  209. return NULL;
  210. LPDIACTIONFORMATW pdup = new DIACTIONFORMATW;
  211. if (!pdup)
  212. return NULL;
  213. if (FAILED(CopyActionFormat(*pdup, *lpAcFor)))
  214. {
  215. delete pdup;
  216. return NULL;
  217. }
  218. return pdup;
  219. }
  220. void FreeActionFormatDup(LPDIACTIONFORMATW &lpAcFor)
  221. {
  222. if (!lpAcFor)
  223. return;
  224. CleanupActionFormatCopy(*lpAcFor);
  225. delete lpAcFor;
  226. lpAcFor = NULL;
  227. }
  228. void TraceActionFormat(LPTSTR header, const DIACTIONFORMATW &acf)
  229. {
  230. #ifdef CFGUI__TRACE_ACTION_FORMATS
  231. tracescope(a, header);
  232. trace(_T("\n"));
  233. traceDWORD(acf.dwSize);
  234. traceDWORD(acf.dwActionSize);
  235. traceDWORD(acf.dwDataSize);
  236. traceDWORD(acf.dwNumActions);
  237. {tracescope(b, _T("acf.rgoAction Array\n"));
  238. for (DWORD i = 0; i < acf.dwNumActions; i++)
  239. {
  240. const DIACTIONW &a = acf.rgoAction[i];
  241. static TCHAR buf[MAX_PATH];
  242. _stprintf(buf, _T("Action %d\n"), i);
  243. {tracescope(c, buf);
  244. traceHEX(a.uAppData);
  245. traceDWORD(a.dwSemantic);
  246. LPTSTR str = AllocActionFlagStr(a.dwFlags);
  247. trace1(_T("a.dwFlags = %s\n"), str);
  248. free(str);
  249. traceWSTR(a.lptszActionName);
  250. traceUINT(a.uResIdString);
  251. traceDWORD(a.dwObjID);
  252. traceGUID(a.guidInstance);
  253. str = AllocActionHowFlagStr(a.dwHow);
  254. trace1(_T("a.dwHow = %s\n"), str);
  255. free(str);
  256. }
  257. }
  258. }
  259. traceGUID(acf.guidActionMap);
  260. traceDWORD(acf.dwGenre);
  261. traceDWORD(acf.dwBufferSize);
  262. traceLONG(acf.lAxisMin);
  263. traceLONG(acf.lAxisMax);
  264. traceHEX(acf.hInstString);
  265. traceHEX(acf.dwCRC);
  266. traceWSTR(acf.tszActionMap);
  267. #endif
  268. }
  269. BOOL IsZeroOrInvalidColorSet(const DICOLORSET &cs)
  270. {
  271. if (cs.dwSize < sizeof(DICOLORSET))
  272. return TRUE;
  273. const int colors = 8;
  274. D3DCOLOR color[colors] = {
  275. cs.cTextFore,
  276. cs.cTextHighlight,
  277. cs.cCalloutLine,
  278. cs.cCalloutHighlight,
  279. cs.cBorder,
  280. cs.cControlFill,
  281. cs.cHighlightFill,
  282. cs.cAreaFill
  283. };
  284. for (int i = 0; i < colors; i++)
  285. if (color[i])
  286. return FALSE;
  287. return TRUE;
  288. }
  289. // D3DCOLOR2COLORREF swaps the blue and red components since GDI and D3D store RGB in the opposite order.
  290. // It also removes the alpha component as the GDI doesn't use that, and including it causes incorrect color.
  291. COLORREF D3DCOLOR2COLORREF(D3DCOLOR c)
  292. {
  293. LPBYTE pC = (LPBYTE)&c;
  294. return (COLORREF)((DWORD(*pC) << 16) + (DWORD(*(pC+1)) << 8) + DWORD(*(pC+2)));
  295. }