Leaked source code of windows server 2003
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.

402 lines
10 KiB

  1. /*-----------------------------------------------------------------------
  2. **
  3. ** Hotkey.c
  4. **
  5. ** Hotkey edit control.
  6. **
  7. **-----------------------------------------------------------------------*/
  8. //
  9. // Win32 REVIEW:
  10. // See all the Get/SetWindowInt().
  11. //
  12. #include "ctlspriv.h"
  13. #define F_EXT 0x01000000L
  14. #define GWU_VIRTKEY 0
  15. #define GWU_MODS 1*sizeof(ULONG_PTR)
  16. #define GWU_INVALID 2*sizeof(ULONG_PTR)
  17. #define GWU_DEFAULT 3*sizeof(ULONG_PTR)
  18. #define GWU_HFONT 4*sizeof(ULONG_PTR)
  19. #define GWU_YFONT 5*sizeof(ULONG_PTR)
  20. #define GWU_HTHEME 6*sizeof(ULONG_PTR)
  21. #define NUM_WND_EXTRA (GWU_HTHEME+sizeof(ULONG_PTR))
  22. LRESULT CALLBACK HotKeyWndProc(HWND hwnd, UINT wMsg, WPARAM wParam, LPARAM lParam);
  23. BOOL InitHotKeyClass(HINSTANCE hInstance)
  24. {
  25. WNDCLASS wc;
  26. wc.lpfnWndProc = HotKeyWndProc;
  27. wc.lpszClassName = s_szHOTKEY_CLASS;
  28. wc.style = CS_GLOBALCLASS;
  29. wc.hInstance = hInstance;
  30. wc.hIcon = NULL;
  31. wc.hCursor = NULL;
  32. wc.hbrBackground = NULL;
  33. wc.lpszMenuName = NULL;
  34. wc.cbClsExtra = 0;
  35. wc.cbWndExtra = NUM_WND_EXTRA;
  36. return (RegisterClass(&wc) || (GetLastError() == ERROR_CLASS_ALREADY_EXISTS));
  37. }
  38. const UINT s_Combos[8] = {
  39. HKCOMB_NONE,
  40. HKCOMB_S,
  41. HKCOMB_C,
  42. HKCOMB_SC,
  43. HKCOMB_A,
  44. HKCOMB_SA,
  45. HKCOMB_CA,
  46. HKCOMB_SCA};
  47. void SetHotKey(HWND hwnd, WORD wVirtKey, WORD wMods, BOOL fSendNotify)
  48. {
  49. /* don't invalidate if it's the same
  50. */
  51. if (wVirtKey == GetWindowInt(hwnd, GWU_VIRTKEY) &&
  52. wMods == GetWindowInt(hwnd, GWU_MODS))
  53. return;
  54. SetWindowInt(hwnd, GWU_VIRTKEY ,wVirtKey);
  55. SetWindowInt(hwnd, GWU_MODS ,wMods);
  56. InvalidateRect(hwnd,NULL,TRUE);
  57. if (fSendNotify) {
  58. FORWARD_WM_COMMAND(GetParent(hwnd), GetDlgCtrlID(hwnd), hwnd, EN_CHANGE, SendMessage);
  59. }
  60. NotifyWinEvent(EVENT_OBJECT_VALUECHANGE, hwnd, OBJID_CLIENT, 0);
  61. }
  62. DWORD GetKeyName(UINT vk, LPTSTR lpsz, DWORD cch, BOOL fExt)
  63. {
  64. LONG scan;
  65. scan = (LONG)MapVirtualKey(vk,0) << 16;
  66. if (fExt)
  67. {
  68. scan |= F_EXT;
  69. }
  70. return (cch > 0) ? GetKeyNameText(scan, lpsz, cch) : 0;
  71. }
  72. void PaintHotKey(register HWND hwnd)
  73. {
  74. TCHAR sz[128];
  75. TCHAR szPlus[10];
  76. int cch;
  77. register HDC hdc;
  78. UINT wMods;
  79. UINT wVirtKey;
  80. PAINTSTRUCT ps;
  81. int x, y;
  82. HANDLE hFont;
  83. LocalizedLoadString(IDS_PLUS, szPlus, ARRAYSIZE(szPlus));
  84. wVirtKey = (UINT) GetWindowInt(hwnd, GWU_VIRTKEY);
  85. wMods = (UINT) GetWindowInt(hwnd, GWU_MODS);
  86. if (wVirtKey || wMods)
  87. {
  88. sz[0] = 0;
  89. cch = 0;
  90. if (wMods & HOTKEYF_CONTROL)
  91. {
  92. GetKeyName(VK_CONTROL, sz, ARRAYSIZE(sz), FALSE);
  93. StringCchCat(sz, ARRAYSIZE(sz), szPlus);
  94. }
  95. if (wMods & HOTKEYF_SHIFT)
  96. {
  97. cch = lstrlen(sz);
  98. GetKeyName(VK_SHIFT, sz+cch, ARRAYSIZE(sz)-cch, FALSE);
  99. StringCchCat(sz, ARRAYSIZE(sz), szPlus);
  100. }
  101. if (wMods & HOTKEYF_ALT)
  102. {
  103. cch = lstrlen(sz);
  104. GetKeyName(VK_MENU, sz+cch, ARRAYSIZE(sz)-cch, FALSE);
  105. StringCchCat(sz, ARRAYSIZE(sz), szPlus);
  106. }
  107. cch = lstrlen(sz);
  108. GetKeyName(wVirtKey, sz+cch, ARRAYSIZE(sz)-cch, wMods & HOTKEYF_EXT);
  109. }
  110. else
  111. {
  112. LocalizedLoadString(IDS_NONE,sz,100);
  113. }
  114. cch = lstrlen(sz);
  115. HideCaret(hwnd);
  116. InvalidateRect(hwnd, NULL, TRUE);
  117. hdc = BeginPaint(hwnd,&ps);
  118. hFont = SelectObject(hdc, (HFONT)GetWindowInt(hwnd,GWU_HFONT));
  119. x = g_cxBorder;
  120. y = g_cyBorder;
  121. if (IsWindowEnabled(hwnd))
  122. {
  123. SetBkColor(hdc, g_clrWindow);
  124. SetTextColor(hdc, g_clrWindowText);
  125. TextOut(hdc,x,y,sz,cch);
  126. }
  127. else
  128. {
  129. // set the background color to Grayed like edit controls
  130. SetBkColor(hdc, g_clrBtnFace);
  131. if (g_clrGrayText)
  132. {
  133. SetTextColor(hdc,g_clrGrayText);
  134. TextOut(hdc,x,y,sz,cch);
  135. }
  136. else
  137. {
  138. GrayString(hdc,NULL,NULL,(ULONG_PTR)(LPTSTR)sz,cch,x,y,0,0);
  139. }
  140. }
  141. MGetTextExtent(hdc, sz, cch, &x, NULL);
  142. if (GetFocus() == hwnd)
  143. SetCaretPos(x+g_cxBorder,
  144. g_cyBorder);
  145. ShowCaret(hwnd);
  146. EndPaint(hwnd,&ps);
  147. }
  148. void HKMSetRules(HWND hwnd, WPARAM wParam, LPARAM lParam)
  149. {
  150. SetWindowInt(hwnd, GWU_INVALID, wParam);
  151. SetWindowInt(hwnd, GWU_DEFAULT, lParam);
  152. }
  153. HFONT HKMSetFont(HWND hwnd, HFONT wParam)
  154. {
  155. HFONT lParam;
  156. HDC hdc;
  157. INT cy;
  158. lParam = (HFONT)GetWindowInt(hwnd,GWU_HFONT);
  159. SetWindowInt(hwnd,GWU_HFONT,(LONG_PTR)wParam);
  160. hdc = GetDC(hwnd);
  161. if (wParam)
  162. wParam = SelectObject(hdc, wParam);
  163. MGetTextExtent(hdc, TEXT("C"), 1, NULL, &cy);
  164. SetWindowInt(hwnd,GWU_YFONT,cy);
  165. if (wParam)
  166. SelectObject(hdc, wParam);
  167. ReleaseDC(hwnd,hdc);
  168. InvalidateRect(hwnd,NULL,TRUE);
  169. return lParam;
  170. }
  171. LRESULT CALLBACK HotKeyWndProc(HWND hwnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
  172. {
  173. WORD wVirtKey;
  174. WORD wMods;
  175. RECT rc;
  176. HDC hdc;
  177. switch (wMsg)
  178. {
  179. case WM_NCCREATE:
  180. SetWindowBits(hwnd, GWL_EXSTYLE, WS_EX_CLIENTEDGE, WS_EX_CLIENTEDGE);
  181. InitGlobalColors();
  182. return TRUE;
  183. case WM_CREATE:
  184. {
  185. HTHEME hTheme;
  186. SetHotKey(hwnd, 0, 0, FALSE);
  187. HKMSetRules(hwnd, 0, 0);
  188. HKMSetFont(hwnd, g_hfontSystem);
  189. hTheme = OpenThemeData(hwnd, L"Combobox");
  190. if (hTheme)
  191. SetWindowLongPtr(hwnd, GWU_HTHEME, (ULONG_PTR)hTheme);
  192. }
  193. break;
  194. case WM_DESTROY:
  195. {
  196. HTHEME hTheme = (HTHEME)GetWindowLongPtr(hwnd, GWU_HTHEME);
  197. if (hTheme)
  198. CloseThemeData(hTheme);
  199. }
  200. break;
  201. case WM_NCPAINT:
  202. {
  203. HTHEME hTheme = (HTHEME)GetWindowLongPtr(hwnd, GWU_HTHEME);
  204. if (hTheme)
  205. {
  206. HRGN hrgn = (wParam != 1) ? (HRGN)wParam : NULL;
  207. HBRUSH hbr = (HBRUSH)GetClassLongPtr(hwnd, GCLP_HBRBACKGROUND);
  208. if (CCDrawNonClientTheme(hTheme, hwnd, hrgn, hbr, 0, CBXS_NORMAL))
  209. {
  210. break;
  211. }
  212. }
  213. }
  214. goto DoDefault;
  215. case WM_THEMECHANGED:
  216. {
  217. HTHEME hTheme = (HTHEME)GetWindowLongPtr(hwnd, GWU_HTHEME);
  218. if (hTheme)
  219. CloseThemeData(hTheme);
  220. hTheme = OpenThemeData(hwnd, L"Combobox");
  221. SetWindowLongPtr(hwnd, GWU_HTHEME, (ULONG_PTR)hTheme); // Set a NULL if OpenThemeData fails
  222. }
  223. break;
  224. case WM_SETFOCUS:
  225. InvalidateRect(hwnd,NULL,TRUE);
  226. CreateCaret(hwnd,NULL,0,(int)GetWindowInt(hwnd,GWU_YFONT));
  227. ShowCaret(hwnd);
  228. break;
  229. case WM_KILLFOCUS:
  230. if (!GetWindowInt(hwnd, GWU_VIRTKEY))
  231. SetHotKey(hwnd, 0, 0, TRUE);
  232. DestroyCaret();
  233. break;
  234. case WM_GETDLGCODE:
  235. return DLGC_WANTCHARS | DLGC_WANTARROWS; // | DLGC_WANTALLKEYS;
  236. case HKM_SETHOTKEY:
  237. SetHotKey(hwnd, LOBYTE(wParam), HIBYTE(wParam), FALSE);
  238. break;
  239. case HKM_GETHOTKEY:
  240. return (256*(BYTE)GetWindowInt(hwnd, GWU_MODS)) +
  241. ((BYTE)GetWindowInt(hwnd, GWU_VIRTKEY));
  242. break;
  243. case HKM_SETRULES:
  244. HKMSetRules(hwnd, wParam, LOWORD(lParam));
  245. break;
  246. case WM_LBUTTONDOWN:
  247. SetFocus(hwnd);
  248. break;
  249. case WM_SYSKEYDOWN:
  250. case WM_KEYDOWN:
  251. switch (wParam)
  252. {
  253. case VK_RETURN:
  254. case VK_TAB:
  255. case VK_SPACE:
  256. case VK_DELETE:
  257. case VK_ESCAPE:
  258. case VK_BACK:
  259. case VK_LWIN:
  260. case VK_RWIN:
  261. case VK_APPS:
  262. SetHotKey(hwnd, 0, 0, TRUE);
  263. return DefWindowProc(hwnd,wMsg,wParam,lParam);
  264. case VK_MENU:
  265. case VK_SHIFT:
  266. case VK_CONTROL:
  267. wVirtKey = 0;
  268. goto SetNewHotKey;
  269. default:
  270. wVirtKey = (WORD) wParam;
  271. SetNewHotKey:
  272. wMods = 0;
  273. if (GetKeyState(VK_CONTROL) < 0)
  274. wMods |= HOTKEYF_CONTROL;
  275. if (GetKeyState(VK_SHIFT) < 0)
  276. wMods |= HOTKEYF_SHIFT;
  277. if (GetKeyState(VK_MENU) < 0)
  278. wMods |= HOTKEYF_ALT;
  279. #define IsFUNKEY(vk) ((vk) >= VK_F1 && (vk) <= VK_F24)
  280. #define IsNUMKEY(vk) ((vk) >= VK_NUMPAD0 && (vk) <= VK_DIVIDE)
  281. //
  282. // dont enforce any rules on the Function keys or
  283. // on the number pad keys.
  284. //
  285. // if this combination is invalid, use the default
  286. if (!IsFUNKEY(wVirtKey) &&
  287. !IsNUMKEY(wVirtKey) &&
  288. (s_Combos[wMods] & GetWindowInt(hwnd, GWU_INVALID)))
  289. {
  290. wMods = (WORD)GetWindowInt(hwnd, GWU_DEFAULT);
  291. }
  292. if (lParam & F_EXT)
  293. wMods |= HOTKEYF_EXT;
  294. SetHotKey(hwnd, wVirtKey, wMods, TRUE);
  295. break;
  296. }
  297. break;
  298. case WM_SYSKEYUP:
  299. case WM_CHAR:
  300. case WM_SYSCHAR:
  301. case WM_KEYUP:
  302. if (!GetWindowInt(hwnd, GWU_VIRTKEY))
  303. SetHotKey(hwnd, 0, 0, TRUE);
  304. break;
  305. case WM_GETFONT:
  306. return GetWindowInt(hwnd,GWU_HFONT);
  307. case WM_SETFONT:
  308. return (LRESULT)(UINT_PTR)HKMSetFont(hwnd, (HFONT)wParam);
  309. case WM_PAINT:
  310. PaintHotKey(hwnd);
  311. break;
  312. case WM_ERASEBKGND:
  313. HideCaret(hwnd);
  314. hdc = GetDC(hwnd);
  315. GetClientRect(hwnd, &rc);
  316. if (IsWindowEnabled(hwnd)) {
  317. FillRect(hdc, &rc, g_hbrWindow);
  318. } else {
  319. FillRect(hdc, &rc, g_hbrBtnFace);
  320. }
  321. ReleaseDC(hwnd, hdc);
  322. // lParam = DefWindowProc(hwnd,wMsg,wParam,lParam);
  323. ShowCaret(hwnd);
  324. return TRUE;
  325. case WM_GETOBJECT:
  326. if( lParam == OBJID_QUERYCLASSNAMEIDX )
  327. return MSAA_CLASSNAMEIDX_HOTKEY;
  328. goto DoDefault;
  329. case WM_ENABLE:
  330. InvalidateRect(hwnd, NULL, TRUE);
  331. goto DoDefault;
  332. default:
  333. DoDefault:
  334. return DefWindowProc(hwnd,wMsg,wParam,lParam);
  335. }
  336. return 0L;
  337. }