We no longer use the .exe.spec.c files.
[wine/multimedia.git] / dlls / comctl32 / hotkey.c
blob1a6b1c754f464ad8d4153ec8e6d3d65f486f742e
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 <stdarg.h>
26 #include <string.h>
27 #include "windef.h"
28 #include "winbase.h"
29 #include "wingdi.h"
30 #include "winuser.h"
31 #include "winnls.h"
32 #include "commctrl.h"
33 #include "comctl32.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(hotkey);
38 typedef struct tagHOTKEY_INFO
40 HWND hwndSelf;
41 HWND hwndNotify;
42 HFONT hFont;
43 BOOL bFocus;
44 INT nHeight;
45 WORD HotKey;
46 WORD InvComb;
47 WORD InvMod;
48 BYTE CurrMod;
49 INT CaretPos;
50 DWORD ScanCode;
51 WCHAR strNone[15]; /* hope its long enough ... */
52 } HOTKEY_INFO;
54 #define HOTKEY_GetInfoPtr(hwnd) ((HOTKEY_INFO *)GetWindowLongA (hwnd, 0))
56 static const WCHAR HOTKEY_plussep[] = { ' ', '+', ' ' };
58 #define IsOnlySet(flags) (infoPtr->CurrMod == (flags))
60 static BOOL
61 HOTKEY_IsCombInv(HOTKEY_INFO *infoPtr)
63 TRACE("(infoPtr=%p)\n", infoPtr);
64 if((infoPtr->InvComb & HKCOMB_NONE) && !infoPtr->CurrMod)
65 return TRUE;
66 if((infoPtr->InvComb & HKCOMB_S) && IsOnlySet(HOTKEYF_SHIFT))
67 return TRUE;
68 if((infoPtr->InvComb & HKCOMB_C) && IsOnlySet(HOTKEYF_CONTROL))
69 return TRUE;
70 if((infoPtr->InvComb & HKCOMB_A) && IsOnlySet(HOTKEYF_ALT))
71 return TRUE;
72 if((infoPtr->InvComb & HKCOMB_SC) &&
73 IsOnlySet(HOTKEYF_SHIFT | HOTKEYF_CONTROL))
74 return TRUE;
75 if((infoPtr->InvComb & HKCOMB_SA) && IsOnlySet(HOTKEYF_SHIFT | HOTKEYF_ALT))
76 return TRUE;
77 if((infoPtr->InvComb & HKCOMB_CA) &&
78 IsOnlySet(HOTKEYF_CONTROL | HOTKEYF_ALT))
79 return TRUE;
80 if((infoPtr->InvComb & HKCOMB_SCA) &&
81 IsOnlySet(HOTKEYF_SHIFT | HOTKEYF_CONTROL | HOTKEYF_ALT))
82 return TRUE;
84 TRACE("() Modifiers are valid\n");
85 return FALSE;
87 #undef IsOnlySet
89 static void
90 HOTKEY_DrawHotKey(HOTKEY_INFO *infoPtr, LPCWSTR KeyName, WORD NameLen,
91 LPRECT rc, HDC hdc)
93 SIZE TextSize;
94 DWORD dwExStyle = GetWindowLongW (infoPtr->hwndSelf, GWL_EXSTYLE);
96 /* We have to allow some space for the frame to be drawn */
97 rc->left += 2;
98 rc->top++;
99 DrawTextW(hdc, KeyName, NameLen, rc, DT_LEFT | DT_VCENTER);
100 rc->left -= 2;
101 rc->top--;
102 if(dwExStyle & WS_EX_CLIENTEDGE)
103 DrawEdge(hdc, rc, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
105 /* Get the text size and position the caret accordingly */
106 GetTextExtentPoint32W (hdc, KeyName, NameLen, &TextSize);
107 infoPtr->CaretPos = TextSize.cx + 2;
108 SetCaretPos(infoPtr->CaretPos, 3);
111 /* Draw the names of the keys in the control */
112 static void
113 HOTKEY_Refresh(HOTKEY_INFO *infoPtr, HDC hdc)
115 WCHAR KeyName[sizeof(WCHAR) * 64];
116 WORD NameLen = 0;
117 BYTE Modifier;
118 RECT rc;
120 GetClientRect(infoPtr->hwndSelf, &rc);
122 TRACE("(infoPtr=%p hdc=%p)\n", infoPtr, hdc);
124 if(!infoPtr->CurrMod && !infoPtr->HotKey) {
125 HOTKEY_DrawHotKey (infoPtr, infoPtr->strNone, 4, &rc, hdc);
126 return;
129 if(infoPtr->HotKey)
130 Modifier = HIBYTE(infoPtr->HotKey);
131 else if(HOTKEY_IsCombInv(infoPtr))
132 Modifier = infoPtr->InvMod;
133 else
134 Modifier = infoPtr->CurrMod;
136 if(Modifier & HOTKEYF_CONTROL) {
137 GetKeyNameTextW(MAKELPARAM(0, MapVirtualKeyW(VK_CONTROL, 0)),
138 KeyName, 64);
139 NameLen = lstrlenW(KeyName);
140 memcpy(&KeyName[NameLen], HOTKEY_plussep, sizeof(HOTKEY_plussep));
141 NameLen += 3;
143 if(Modifier & HOTKEYF_SHIFT) {
144 GetKeyNameTextW(MAKELPARAM(0, MapVirtualKeyW(VK_SHIFT, 0)),
145 &KeyName[NameLen], 64 - NameLen);
146 NameLen = lstrlenW(KeyName);
147 memcpy(&KeyName[NameLen], HOTKEY_plussep, sizeof(HOTKEY_plussep));
148 NameLen += 3;
150 if(Modifier & HOTKEYF_ALT) {
151 GetKeyNameTextW(MAKELPARAM(0, MapVirtualKeyW(VK_MENU, 0)),
152 &KeyName[NameLen], 64 - NameLen);
153 NameLen = lstrlenW(KeyName);
154 memcpy(&KeyName[NameLen], HOTKEY_plussep, sizeof(HOTKEY_plussep));
155 NameLen += 3;
158 if(infoPtr->HotKey) {
159 GetKeyNameTextW(infoPtr->ScanCode, &KeyName[NameLen], 64 - NameLen);
160 NameLen = lstrlenW(KeyName);
162 else
163 KeyName[NameLen] = 0;
165 HOTKEY_DrawHotKey (infoPtr, KeyName, NameLen, &rc, hdc);
168 static void
169 HOTKEY_Paint(HOTKEY_INFO *infoPtr, HDC hdc)
171 if (hdc)
172 HOTKEY_Refresh(infoPtr, hdc);
173 else {
174 PAINTSTRUCT ps;
175 hdc = BeginPaint (infoPtr->hwndSelf, &ps);
176 HOTKEY_Refresh (infoPtr, hdc);
177 EndPaint (infoPtr->hwndSelf, &ps);
181 static LRESULT
182 HOTKEY_GetHotKey(HOTKEY_INFO *infoPtr)
184 TRACE("(infoPtr=%p) Modifiers: 0x%x, Virtual Key: %d\n", infoPtr,
185 HIBYTE(infoPtr->HotKey), LOBYTE(infoPtr->HotKey));
186 return (LRESULT)infoPtr->HotKey;
189 static void
190 HOTKEY_SetHotKey(HOTKEY_INFO *infoPtr, WPARAM wParam)
192 infoPtr->HotKey = (WORD)wParam;
193 infoPtr->ScanCode =
194 MAKELPARAM(0, MapVirtualKeyW(LOBYTE(infoPtr->HotKey), 0));
195 TRACE("(infoPtr=%p wParam=%x) Modifiers: 0x%x, Virtual Key: %d\n", infoPtr,
196 wParam, HIBYTE(infoPtr->HotKey), LOBYTE(infoPtr->HotKey));
197 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
200 static void
201 HOTKEY_SetRules(HOTKEY_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
203 infoPtr->InvComb = (WORD)wParam;
204 infoPtr->InvMod = (WORD)lParam;
205 TRACE("(infoPtr=%p) Invalid Modifers: 0x%x, If Invalid: 0x%x\n", infoPtr,
206 infoPtr->InvComb, infoPtr->InvMod);
209 /* << HOTKEY_Char >> */
211 static LRESULT
212 HOTKEY_Create (HWND hwnd, WPARAM wParam, LPARAM lParam)
214 HOTKEY_INFO *infoPtr;
215 TEXTMETRICW tm;
216 HDC hdc;
218 /* allocate memory for info structure */
219 infoPtr = (HOTKEY_INFO *)Alloc (sizeof(HOTKEY_INFO));
220 SetWindowLongW (hwnd, 0, (DWORD)infoPtr);
222 /* initialize info structure */
223 infoPtr->HotKey = infoPtr->InvComb = infoPtr->InvMod = infoPtr->CurrMod = 0;
224 infoPtr->CaretPos = 2;
225 infoPtr->hwndSelf = hwnd;
226 infoPtr->hwndNotify = ((LPCREATESTRUCTA)lParam)->hwndParent;
227 LoadStringW(COMCTL32_hModule, HKY_NONE, infoPtr->strNone, 15);
229 /* get default font height */
230 hdc = GetDC (hwnd);
231 GetTextMetricsW (hdc, &tm);
232 infoPtr->nHeight = tm.tmHeight;
233 ReleaseDC (hwnd, hdc);
235 return 0;
239 static LRESULT
240 HOTKEY_Destroy (HOTKEY_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
242 HWND hwnd = infoPtr->hwndSelf;
243 /* free hotkey info data */
244 Free (infoPtr);
245 SetWindowLongW (hwnd, 0, 0);
246 return 0;
250 static LRESULT
251 HOTKEY_EraseBackground (HOTKEY_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
253 HBRUSH hBrush;
254 RECT rc;
256 hBrush =
257 (HBRUSH)SendMessageW (infoPtr->hwndNotify, WM_CTLCOLOREDIT,
258 wParam, (LPARAM)infoPtr->hwndSelf);
259 if (hBrush)
260 hBrush = (HBRUSH)GetStockObject (WHITE_BRUSH);
261 GetClientRect (infoPtr->hwndSelf, &rc);
263 FillRect ((HDC)wParam, &rc, hBrush);
265 return -1;
269 inline static LRESULT
270 HOTKEY_GetFont (HOTKEY_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
272 return (LRESULT)infoPtr->hFont;
275 static LRESULT
276 HOTKEY_KeyDown (HOTKEY_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
278 TRACE("() Key: %d\n", wParam);
279 /* If any key is Pressed, we have to reset the hotkey in the control */
280 infoPtr->HotKey = 0;
282 switch (wParam) {
283 case VK_RETURN:
284 case VK_TAB:
285 case VK_SPACE:
286 case VK_DELETE:
287 case VK_ESCAPE:
288 case VK_BACK:
289 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
290 return DefWindowProcW (infoPtr->hwndSelf, WM_KEYDOWN, wParam,
291 lParam);
293 case VK_SHIFT:
294 infoPtr->CurrMod |= HOTKEYF_SHIFT;
295 break;
296 case VK_CONTROL:
297 infoPtr->CurrMod |= HOTKEYF_CONTROL;
298 break;
299 case VK_MENU:
300 infoPtr->CurrMod |= HOTKEYF_ALT;
301 break;
303 default:
304 if(HOTKEY_IsCombInv(infoPtr))
305 infoPtr->HotKey = MAKEWORD(wParam, infoPtr->InvMod);
306 else
307 infoPtr->HotKey = MAKEWORD(wParam, infoPtr->CurrMod);
308 infoPtr->ScanCode = lParam;
309 break;
312 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
313 return 0;
317 static LRESULT
318 HOTKEY_KeyUp (HOTKEY_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
320 TRACE("() Key: %d\n", wParam);
321 switch (wParam) {
322 case VK_SHIFT:
323 infoPtr->CurrMod &= ~HOTKEYF_SHIFT;
324 break;
325 case VK_CONTROL:
326 infoPtr->CurrMod &= ~HOTKEYF_CONTROL;
327 break;
328 case VK_MENU:
329 infoPtr->CurrMod &= ~HOTKEYF_ALT;
330 break;
331 default:
332 return 1;
335 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
337 return 0;
341 static LRESULT
342 HOTKEY_KillFocus (HOTKEY_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
344 infoPtr->bFocus = FALSE;
345 DestroyCaret ();
347 return 0;
351 static LRESULT
352 HOTKEY_LButtonDown (HOTKEY_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
354 SetFocus (infoPtr->hwndSelf);
356 return 0;
360 inline static LRESULT
361 HOTKEY_NCCreate (HOTKEY_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
363 DWORD dwExStyle = GetWindowLongW (infoPtr->hwndSelf, GWL_EXSTYLE);
364 SetWindowLongW (infoPtr->hwndSelf, GWL_EXSTYLE,
365 dwExStyle | WS_EX_CLIENTEDGE);
366 return DefWindowProcW (infoPtr->hwndSelf, WM_NCCREATE, wParam, lParam);
369 static LRESULT
370 HOTKEY_SetFocus (HOTKEY_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
372 infoPtr->bFocus = TRUE;
375 CreateCaret (infoPtr->hwndSelf, NULL, 1, infoPtr->nHeight - 2);
377 SetCaretPos (infoPtr->CaretPos, 3);
379 ShowCaret (infoPtr->hwndSelf);
382 return 0;
386 inline static LRESULT
387 HOTKEY_SetFont (HOTKEY_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
389 TEXTMETRICW tm;
390 HDC hdc;
391 HFONT hOldFont = 0;
393 infoPtr->hFont = (HFONT)wParam;
395 hdc = GetDC (infoPtr->hwndSelf);
396 if (infoPtr->hFont)
397 hOldFont = SelectObject (hdc, infoPtr->hFont);
399 GetTextMetricsW (hdc, &tm);
400 infoPtr->nHeight = tm.tmHeight;
402 if (infoPtr->hFont)
403 SelectObject (hdc, hOldFont);
404 ReleaseDC (infoPtr->hwndSelf, hdc);
406 if (LOWORD(lParam))
407 InvalidateRect (infoPtr->hwndSelf, NULL, TRUE);
409 return 0;
412 static LRESULT WINAPI
413 HOTKEY_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
415 HOTKEY_INFO *infoPtr = HOTKEY_GetInfoPtr (hwnd);
416 TRACE("hwnd=%p msg=%x wparam=%x lparam=%lx\n", hwnd, uMsg, wParam, lParam);
417 if (!infoPtr && (uMsg != WM_CREATE))
418 return DefWindowProcW (hwnd, uMsg, wParam, lParam);
419 switch (uMsg)
421 case HKM_GETHOTKEY:
422 return HOTKEY_GetHotKey (infoPtr);
423 case HKM_SETHOTKEY:
424 HOTKEY_SetHotKey (infoPtr, wParam);
425 break;
426 case HKM_SETRULES:
427 HOTKEY_SetRules (infoPtr, wParam, lParam);
428 break;
430 /* case WM_CHAR: */
432 case WM_CREATE:
433 return HOTKEY_Create (hwnd, wParam, lParam);
435 case WM_DESTROY:
436 return HOTKEY_Destroy (infoPtr, wParam, lParam);
438 case WM_ERASEBKGND:
439 return HOTKEY_EraseBackground (infoPtr, wParam, lParam);
441 case WM_GETDLGCODE:
442 return DLGC_WANTCHARS | DLGC_WANTARROWS;
444 case WM_GETFONT:
445 return HOTKEY_GetFont (infoPtr, wParam, lParam);
447 case WM_KEYDOWN:
448 case WM_SYSKEYDOWN:
449 return HOTKEY_KeyDown (infoPtr, wParam, lParam);
451 case WM_KEYUP:
452 case WM_SYSKEYUP:
453 return HOTKEY_KeyUp (infoPtr, wParam, lParam);
455 case WM_KILLFOCUS:
456 return HOTKEY_KillFocus (infoPtr, wParam, lParam);
458 case WM_LBUTTONDOWN:
459 return HOTKEY_LButtonDown (infoPtr, wParam, lParam);
461 case WM_NCCREATE:
462 return HOTKEY_NCCreate (infoPtr, wParam, lParam);
464 case WM_PAINT:
465 HOTKEY_Paint(infoPtr, (HDC)wParam);
466 return 0;
468 case WM_SETFOCUS:
469 return HOTKEY_SetFocus (infoPtr, wParam, lParam);
471 case WM_SETFONT:
472 return HOTKEY_SetFont (infoPtr, wParam, lParam);
474 /* case WM_SYSCHAR: */
476 default:
477 if ((uMsg >= WM_USER) && (uMsg < WM_APP))
478 ERR("unknown msg %04x wp=%08x lp=%08lx\n",
479 uMsg, wParam, lParam);
480 return DefWindowProcW (hwnd, uMsg, wParam, lParam);
482 return 0;
486 void
487 HOTKEY_Register (void)
489 WNDCLASSW wndClass;
491 ZeroMemory (&wndClass, sizeof(WNDCLASSW));
492 wndClass.style = CS_GLOBALCLASS;
493 wndClass.lpfnWndProc = (WNDPROC)HOTKEY_WindowProc;
494 wndClass.cbClsExtra = 0;
495 wndClass.cbWndExtra = sizeof(HOTKEY_INFO *);
496 wndClass.hCursor = 0;
497 wndClass.hbrBackground = 0;
498 wndClass.lpszClassName = HOTKEY_CLASSW;
500 RegisterClassW (&wndClass);
504 void
505 HOTKEY_Unregister (void)
507 UnregisterClassW (HOTKEY_CLASSW, NULL);