Removed unnecessary HANDLE typecasts.
[wine/hacks.git] / dlls / comctl32 / hotkey.c
blob5eb288c91e0339171751656240784d0c25ac680b
1 /*
2 * Hotkey control
4 * Copyright 1998, 1999 Eric Kohl
5 * Copyright 2002 Gyorgy 'Nog' Jeney
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 * TODO:
22 * - What are we meant to do with the WM_CHAR message?
25 #include <string.h>
26 #include "winbase.h"
27 #include "commctrl.h"
28 #include "comctl32.h"
29 #include "wine/debug.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(hotkey);
33 typedef struct tagHOTKEY_INFO
35 HWND hwndSelf;
36 HFONT hFont;
37 BOOL bFocus;
38 INT nHeight;
39 WORD HotKey;
40 WORD InvComb;
41 WORD InvMod;
42 BYTE CurrMod;
43 INT CaretPos;
44 DWORD ScanCode;
45 WCHAR strNone[15]; /* hope its long enough ... */
46 } HOTKEY_INFO;
48 #define HOTKEY_GetInfoPtr(hwnd) ((HOTKEY_INFO *)GetWindowLongA (hwnd, 0))
50 static const WCHAR HOTKEY_plussep[] = { ' ', '+', ' ' };
52 #define IsOnlySet(flags) (infoPtr->CurrMod == (flags))
54 static BOOL
55 HOTKEY_IsCombInv(HOTKEY_INFO *infoPtr)
57 TRACE("(infoPtr=%p)\n", infoPtr);
58 if((infoPtr->InvComb & HKCOMB_NONE) && !infoPtr->CurrMod)
59 return TRUE;
60 if((infoPtr->InvComb & HKCOMB_S) && IsOnlySet(HOTKEYF_SHIFT))
61 return TRUE;
62 if((infoPtr->InvComb & HKCOMB_C) && IsOnlySet(HOTKEYF_CONTROL))
63 return TRUE;
64 if((infoPtr->InvComb & HKCOMB_A) && IsOnlySet(HOTKEYF_ALT))
65 return TRUE;
66 if((infoPtr->InvComb & HKCOMB_SC) &&
67 IsOnlySet(HOTKEYF_SHIFT | HOTKEYF_CONTROL))
68 return TRUE;
69 if((infoPtr->InvComb & HKCOMB_SA) && IsOnlySet(HOTKEYF_SHIFT | HOTKEYF_ALT))
70 return TRUE;
71 if((infoPtr->InvComb & HKCOMB_CA) &&
72 IsOnlySet(HOTKEYF_CONTROL | HOTKEYF_ALT))
73 return TRUE;
74 if((infoPtr->InvComb & HKCOMB_SCA) &&
75 IsOnlySet(HOTKEYF_SHIFT | HOTKEYF_CONTROL | HOTKEYF_ALT))
76 return TRUE;
78 TRACE("() Modifiers are valid\n");
79 return FALSE;
81 #undef IsOnlySet
83 static void
84 HOTKEY_DrawHotKey(HOTKEY_INFO *infoPtr, LPCWSTR KeyName, WORD NameLen,
85 LPRECT rc, HDC hdc)
87 SIZE TextSize;
88 DWORD dwExStyle = GetWindowLongW (infoPtr->hwndSelf, GWL_EXSTYLE);
90 /* We have to allow some space for the frame to be drawn */
91 rc->left += 2;
92 rc->top++;
93 DrawTextW(hdc, KeyName, NameLen, rc, DT_LEFT | DT_VCENTER);
94 rc->left -= 2;
95 rc->top--;
96 if(dwExStyle & WS_EX_CLIENTEDGE)
97 DrawEdge(hdc, rc, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
99 /* Get the text size and position the caret accordingly */
100 GetTextExtentPoint32W (hdc, KeyName, NameLen, &TextSize);
101 infoPtr->CaretPos = TextSize.cx + 2;
102 SetCaretPos(infoPtr->CaretPos, 3);
105 /* Draw the names of the keys in the control */
106 static void
107 HOTKEY_Refresh(HOTKEY_INFO *infoPtr, HDC hdc)
109 WCHAR KeyName[sizeof(WCHAR) * 64];
110 WORD NameLen = 0;
111 BYTE Modifier;
112 RECT rc;
114 GetClientRect(infoPtr->hwndSelf, &rc);
116 TRACE("(infoPtr=%p hdc=%p)\n", infoPtr, hdc);
118 if(!infoPtr->CurrMod && !infoPtr->HotKey) {
119 HOTKEY_DrawHotKey (infoPtr, infoPtr->strNone, 4, &rc, hdc);
120 return;
123 if(infoPtr->HotKey)
124 Modifier = HIBYTE(infoPtr->HotKey);
125 else if(HOTKEY_IsCombInv(infoPtr))
126 Modifier = infoPtr->InvMod;
127 else
128 Modifier = infoPtr->CurrMod;
130 if(Modifier & HOTKEYF_CONTROL) {
131 GetKeyNameTextW(MAKELPARAM(0, MapVirtualKeyW(VK_CONTROL, 0)),
132 KeyName, 64);
133 NameLen = lstrlenW(KeyName);
134 memcpy(&KeyName[NameLen], HOTKEY_plussep, sizeof(HOTKEY_plussep));
135 NameLen += 3;
137 if(Modifier & HOTKEYF_SHIFT) {
138 GetKeyNameTextW(MAKELPARAM(0, MapVirtualKeyW(VK_SHIFT, 0)),
139 &KeyName[NameLen], 64 - NameLen);
140 NameLen = lstrlenW(KeyName);
141 memcpy(&KeyName[NameLen], HOTKEY_plussep, sizeof(HOTKEY_plussep));
142 NameLen += 3;
144 if(Modifier & HOTKEYF_ALT) {
145 GetKeyNameTextW(MAKELPARAM(0, MapVirtualKeyW(VK_MENU, 0)),
146 &KeyName[NameLen], 64 - NameLen);
147 NameLen = lstrlenW(KeyName);
148 memcpy(&KeyName[NameLen], HOTKEY_plussep, sizeof(HOTKEY_plussep));
149 NameLen += 3;
152 if(infoPtr->HotKey) {
153 GetKeyNameTextW(infoPtr->ScanCode, &KeyName[NameLen], 64 - NameLen);
154 NameLen = lstrlenW(KeyName);
156 else
157 KeyName[NameLen] = 0;
159 HOTKEY_DrawHotKey (infoPtr, KeyName, NameLen, &rc, hdc);
162 static void
163 HOTKEY_Paint(HOTKEY_INFO *infoPtr, HDC hdc)
165 if (hdc)
166 HOTKEY_Refresh(infoPtr, hdc);
167 else {
168 PAINTSTRUCT ps;
169 hdc = BeginPaint (infoPtr->hwndSelf, &ps);
170 HOTKEY_Refresh (infoPtr, hdc);
171 EndPaint (infoPtr->hwndSelf, &ps);
175 static LRESULT
176 HOTKEY_GetHotKey(HOTKEY_INFO *infoPtr)
178 TRACE("(infoPtr=%p) Modifiers: 0x%x, Virtual Key: %d\n", infoPtr,
179 HIBYTE(infoPtr->HotKey), LOBYTE(infoPtr->HotKey));
180 return (LRESULT)infoPtr->HotKey;
183 static void
184 HOTKEY_SetHotKey(HOTKEY_INFO *infoPtr, WPARAM wParam)
186 infoPtr->HotKey = (WORD)wParam;
187 infoPtr->ScanCode =
188 MAKELPARAM(0, MapVirtualKeyW(LOBYTE(infoPtr->HotKey), 0));
189 TRACE("(infoPtr=%p wParam=%x) Modifiers: 0x%x, Virtual Key: %d\n", infoPtr,
190 wParam, HIBYTE(infoPtr->HotKey), LOBYTE(infoPtr->HotKey));
191 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
194 static void
195 HOTKEY_SetRules(HOTKEY_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
197 infoPtr->InvComb = (WORD)wParam;
198 infoPtr->InvMod = (WORD)lParam;
199 TRACE("(infoPtr=%p) Invalid Modifers: 0x%x, If Invalid: 0x%x\n", infoPtr,
200 infoPtr->InvComb, infoPtr->InvMod);
203 /* << HOTKEY_Char >> */
205 static LRESULT
206 HOTKEY_Create (HWND hwnd, WPARAM wParam, LPARAM lParam)
208 HOTKEY_INFO *infoPtr;
209 TEXTMETRICW tm;
210 HDC hdc;
212 /* allocate memory for info structure */
213 infoPtr = (HOTKEY_INFO *)COMCTL32_Alloc (sizeof(HOTKEY_INFO));
214 SetWindowLongW (hwnd, 0, (DWORD)infoPtr);
216 /* initialize info structure */
217 infoPtr->HotKey = infoPtr->InvComb = infoPtr->InvMod = infoPtr->CurrMod = 0;
218 infoPtr->CaretPos = 2;
219 infoPtr->hwndSelf = hwnd;
220 LoadStringW(COMCTL32_hModule, HKY_NONE, infoPtr->strNone, 15);
222 /* get default font height */
223 hdc = GetDC (hwnd);
224 GetTextMetricsW (hdc, &tm);
225 infoPtr->nHeight = tm.tmHeight;
226 ReleaseDC (hwnd, hdc);
228 return 0;
232 static LRESULT
233 HOTKEY_Destroy (HOTKEY_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
235 HWND hwnd = infoPtr->hwndSelf;
236 /* free hotkey info data */
237 COMCTL32_Free (infoPtr);
238 SetWindowLongW (hwnd, 0, 0);
239 return 0;
243 static LRESULT
244 HOTKEY_EraseBackground (HOTKEY_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
246 HBRUSH hBrush;
247 RECT rc;
249 hBrush =
250 (HBRUSH)SendMessageW (GetParent (infoPtr->hwndSelf), WM_CTLCOLOREDIT,
251 wParam, (LPARAM)infoPtr->hwndSelf);
252 if (hBrush)
253 hBrush = (HBRUSH)GetStockObject (WHITE_BRUSH);
254 GetClientRect (infoPtr->hwndSelf, &rc);
256 FillRect ((HDC)wParam, &rc, hBrush);
258 return -1;
262 inline static LRESULT
263 HOTKEY_GetFont (HOTKEY_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
265 return (LRESULT)infoPtr->hFont;
268 static LRESULT
269 HOTKEY_KeyDown (HOTKEY_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
271 TRACE("() Key: %d\n", wParam);
272 /* If any key is Pressed, we have to reset the hotkey in the control */
273 infoPtr->HotKey = 0;
275 switch (wParam) {
276 case VK_RETURN:
277 case VK_TAB:
278 case VK_SPACE:
279 case VK_DELETE:
280 case VK_ESCAPE:
281 case VK_BACK:
282 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
283 return DefWindowProcW (infoPtr->hwndSelf, WM_KEYDOWN, wParam,
284 lParam);
286 case VK_SHIFT:
287 infoPtr->CurrMod |= HOTKEYF_SHIFT;
288 break;
289 case VK_CONTROL:
290 infoPtr->CurrMod |= HOTKEYF_CONTROL;
291 break;
292 case VK_MENU:
293 infoPtr->CurrMod |= HOTKEYF_ALT;
294 break;
296 default:
297 if(HOTKEY_IsCombInv(infoPtr))
298 infoPtr->HotKey = MAKEWORD(wParam, infoPtr->InvMod);
299 else
300 infoPtr->HotKey = MAKEWORD(wParam, infoPtr->CurrMod);
301 infoPtr->ScanCode = lParam;
302 break;
305 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
306 return 0;
310 static LRESULT
311 HOTKEY_KeyUp (HOTKEY_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
313 TRACE("() Key: %d\n", wParam);
314 switch (wParam) {
315 case VK_SHIFT:
316 infoPtr->CurrMod &= ~HOTKEYF_SHIFT;
317 break;
318 case VK_CONTROL:
319 infoPtr->CurrMod &= ~HOTKEYF_CONTROL;
320 break;
321 case VK_MENU:
322 infoPtr->CurrMod &= ~HOTKEYF_ALT;
323 break;
324 default:
325 return 1;
328 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
330 return 0;
334 static LRESULT
335 HOTKEY_KillFocus (HOTKEY_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
337 infoPtr->bFocus = FALSE;
338 DestroyCaret ();
340 return 0;
344 static LRESULT
345 HOTKEY_LButtonDown (HOTKEY_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
347 SetFocus (infoPtr->hwndSelf);
349 return 0;
353 inline static LRESULT
354 HOTKEY_NCCreate (HOTKEY_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
356 DWORD dwExStyle = GetWindowLongW (infoPtr->hwndSelf, GWL_EXSTYLE);
357 SetWindowLongW (infoPtr->hwndSelf, GWL_EXSTYLE,
358 dwExStyle | WS_EX_CLIENTEDGE);
359 return DefWindowProcW (infoPtr->hwndSelf, WM_NCCREATE, wParam, lParam);
362 static LRESULT
363 HOTKEY_SetFocus (HOTKEY_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
365 infoPtr->bFocus = TRUE;
368 CreateCaret (infoPtr->hwndSelf, NULL, 1, infoPtr->nHeight - 2);
370 SetCaretPos (infoPtr->CaretPos, 3);
372 ShowCaret (infoPtr->hwndSelf);
375 return 0;
379 inline static LRESULT
380 HOTKEY_SetFont (HOTKEY_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
382 TEXTMETRICW tm;
383 HDC hdc;
384 HFONT hOldFont = 0;
386 infoPtr->hFont = (HFONT)wParam;
388 hdc = GetDC (infoPtr->hwndSelf);
389 if (infoPtr->hFont)
390 hOldFont = SelectObject (hdc, infoPtr->hFont);
392 GetTextMetricsW (hdc, &tm);
393 infoPtr->nHeight = tm.tmHeight;
395 if (infoPtr->hFont)
396 SelectObject (hdc, hOldFont);
397 ReleaseDC (infoPtr->hwndSelf, hdc);
399 if (LOWORD(lParam))
400 InvalidateRect (infoPtr->hwndSelf, NULL, TRUE);
402 return 0;
405 static LRESULT WINAPI
406 HOTKEY_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
408 HOTKEY_INFO *infoPtr = HOTKEY_GetInfoPtr (hwnd);
409 TRACE("hwnd=%p msg=%x wparam=%x lparam=%lx\n", hwnd, uMsg, wParam, lParam);
410 if (!infoPtr && (uMsg != WM_CREATE))
411 return DefWindowProcW (hwnd, uMsg, wParam, lParam);
412 switch (uMsg)
414 case HKM_GETHOTKEY:
415 return HOTKEY_GetHotKey (infoPtr);
416 case HKM_SETHOTKEY:
417 HOTKEY_SetHotKey (infoPtr, wParam);
418 break;
419 case HKM_SETRULES:
420 HOTKEY_SetRules (infoPtr, wParam, lParam);
421 break;
423 /* case WM_CHAR: */
425 case WM_CREATE:
426 return HOTKEY_Create (hwnd, wParam, lParam);
428 case WM_DESTROY:
429 return HOTKEY_Destroy (infoPtr, wParam, lParam);
431 case WM_ERASEBKGND:
432 return HOTKEY_EraseBackground (infoPtr, wParam, lParam);
434 case WM_GETDLGCODE:
435 return DLGC_WANTCHARS | DLGC_WANTARROWS;
437 case WM_GETFONT:
438 return HOTKEY_GetFont (infoPtr, wParam, lParam);
440 case WM_KEYDOWN:
441 case WM_SYSKEYDOWN:
442 return HOTKEY_KeyDown (infoPtr, wParam, lParam);
444 case WM_KEYUP:
445 case WM_SYSKEYUP:
446 return HOTKEY_KeyUp (infoPtr, wParam, lParam);
448 case WM_KILLFOCUS:
449 return HOTKEY_KillFocus (infoPtr, wParam, lParam);
451 case WM_LBUTTONDOWN:
452 return HOTKEY_LButtonDown (infoPtr, wParam, lParam);
454 case WM_NCCREATE:
455 return HOTKEY_NCCreate (infoPtr, wParam, lParam);
457 case WM_PAINT:
458 HOTKEY_Paint(infoPtr, (HDC)wParam);
459 return 0;
461 case WM_SETFOCUS:
462 return HOTKEY_SetFocus (infoPtr, wParam, lParam);
464 case WM_SETFONT:
465 return HOTKEY_SetFont (infoPtr, wParam, lParam);
467 /* case WM_SYSCHAR: */
469 default:
470 if ((uMsg >= WM_USER) && (uMsg < WM_APP))
471 ERR("unknown msg %04x wp=%08x lp=%08lx\n",
472 uMsg, wParam, lParam);
473 return DefWindowProcW (hwnd, uMsg, wParam, lParam);
475 return 0;
479 void
480 HOTKEY_Register (void)
482 WNDCLASSW wndClass;
484 ZeroMemory (&wndClass, sizeof(WNDCLASSW));
485 wndClass.style = CS_GLOBALCLASS;
486 wndClass.lpfnWndProc = (WNDPROC)HOTKEY_WindowProc;
487 wndClass.cbClsExtra = 0;
488 wndClass.cbWndExtra = sizeof(HOTKEY_INFO *);
489 wndClass.hCursor = 0;
490 wndClass.hbrBackground = 0;
491 wndClass.lpszClassName = HOTKEY_CLASSW;
493 RegisterClassW (&wndClass);
497 void
498 HOTKEY_Unregister (void)
500 UnregisterClassW (HOTKEY_CLASSW, NULL);