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.

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