source: trunk/src/comctl32/hotkey.c@ 10367

Last change on this file since 10367 was 10097, checked in by sandervl, 22 years ago

Wine resync

File size: 12.5 KB
Line 
1/*
2 * Hotkey control
3 *
4 * Copyright 1998, 1999 Eric Kohl
5 * Copyright 2002 Gyorgy 'Nog' Jeney
6 *
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.
11 *
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.
16 *
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
20 *
21 * TODO:
22 * - What are we meant to do with the WM_CHAR message?
23 */
24
25#include <string.h>
26#include "winbase.h"
27#include "commctrl.h"
28#include "comctl32.h"
29#include "wine/debug.h"
30
31WINE_DEFAULT_DEBUG_CHANNEL(hotkey);
32
33typedef struct tagHOTKEY_INFO
34{
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;
47
48#define HOTKEY_GetInfoPtr(hwnd) ((HOTKEY_INFO *)GetWindowLongA (hwnd, 0))
49
50static const WCHAR HOTKEY_plussep[] = { ' ', '+', ' ' };
51
52#define IsOnlySet(flags) (infoPtr->CurrMod == (flags))
53
54static BOOL
55HOTKEY_IsCombInv(HOTKEY_INFO *infoPtr)
56{
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;
77
78 TRACE("() Modifiers are valid\n");
79 return FALSE;
80}
81#undef IsOnlySet
82
83static void
84HOTKEY_DrawHotKey(HOTKEY_INFO *infoPtr, LPCWSTR KeyName, WORD NameLen,
85 LPRECT rc, HDC hdc)
86{
87 SIZE TextSize;
88 DWORD dwExStyle = GetWindowLongW (infoPtr->hwndSelf, GWL_EXSTYLE);
89
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);
98
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);
103}
104
105/* Draw the names of the keys in the control */
106static void
107HOTKEY_Refresh(HOTKEY_INFO *infoPtr, HDC hdc)
108{
109 WCHAR KeyName[sizeof(WCHAR) * 64];
110 WORD NameLen = 0;
111 BYTE Modifier;
112 RECT rc;
113
114 GetClientRect(infoPtr->hwndSelf, &rc);
115
116 TRACE("(infoPtr=%p hdc=%p)\n", infoPtr, hdc);
117
118 if(!infoPtr->CurrMod && !infoPtr->HotKey) {
119 HOTKEY_DrawHotKey (infoPtr, infoPtr->strNone, 4, &rc, hdc);
120 return;
121 }
122
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;
129
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;
136 }
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;
143 }
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;
150 }
151
152 if(infoPtr->HotKey) {
153 GetKeyNameTextW(infoPtr->ScanCode, &KeyName[NameLen], 64 - NameLen);
154 NameLen = lstrlenW(KeyName);
155 }
156 else
157 KeyName[NameLen] = 0;
158
159 HOTKEY_DrawHotKey (infoPtr, KeyName, NameLen, &rc, hdc);
160}
161
162static void
163HOTKEY_Paint(HOTKEY_INFO *infoPtr, HDC hdc)
164{
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);
172 }
173}
174
175static LRESULT
176HOTKEY_GetHotKey(HOTKEY_INFO *infoPtr)
177{
178 TRACE("(infoPtr=%p) Modifiers: 0x%x, Virtual Key: %d\n", infoPtr,
179 HIBYTE(infoPtr->HotKey), LOBYTE(infoPtr->HotKey));
180 return (LRESULT)infoPtr->HotKey;
181}
182
183static void
184HOTKEY_SetHotKey(HOTKEY_INFO *infoPtr, WPARAM wParam)
185{
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);
192}
193
194static void
195HOTKEY_SetRules(HOTKEY_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
196{
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);
201}
202
203/* << HOTKEY_Char >> */
204
205static LRESULT
206HOTKEY_Create (HWND hwnd, WPARAM wParam, LPARAM lParam)
207{
208 HOTKEY_INFO *infoPtr;
209 TEXTMETRICW tm;
210 HDC hdc;
211
212 /* allocate memory for info structure */
213 infoPtr = (HOTKEY_INFO *)COMCTL32_Alloc (sizeof(HOTKEY_INFO));
214 SetWindowLongW (hwnd, 0, (DWORD)infoPtr);
215
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);
221
222 /* get default font height */
223 hdc = GetDC (hwnd);
224 GetTextMetricsW (hdc, &tm);
225 infoPtr->nHeight = tm.tmHeight;
226 ReleaseDC (hwnd, hdc);
227
228 return 0;
229}
230
231
232static LRESULT
233HOTKEY_Destroy (HOTKEY_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
234{
235 HWND hwnd = infoPtr->hwndSelf;
236 /* free hotkey info data */
237 COMCTL32_Free (infoPtr);
238 SetWindowLongW (hwnd, 0, 0);
239 return 0;
240}
241
242
243static LRESULT
244HOTKEY_EraseBackground (HOTKEY_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
245{
246 HBRUSH hBrush;
247 RECT rc;
248
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);
255
256 FillRect ((HDC)wParam, &rc, hBrush);
257
258 return -1;
259}
260
261
262inline static LRESULT
263HOTKEY_GetFont (HOTKEY_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
264{
265 return (LRESULT)infoPtr->hFont;
266}
267
268static LRESULT
269HOTKEY_KeyDown (HOTKEY_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
270{
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;
274
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);
285
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;
295
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;
303 }
304
305 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
306 return 0;
307}
308
309
310static LRESULT
311HOTKEY_KeyUp (HOTKEY_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
312{
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;
326 }
327
328 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
329
330 return 0;
331}
332
333
334static LRESULT
335HOTKEY_KillFocus (HOTKEY_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
336{
337 infoPtr->bFocus = FALSE;
338 DestroyCaret ();
339
340 return 0;
341}
342
343
344static LRESULT
345HOTKEY_LButtonDown (HOTKEY_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
346{
347 SetFocus (infoPtr->hwndSelf);
348
349 return 0;
350}
351
352
353inline static LRESULT
354HOTKEY_NCCreate (HOTKEY_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
355{
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);
360}
361
362static LRESULT
363HOTKEY_SetFocus (HOTKEY_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
364{
365 infoPtr->bFocus = TRUE;
366
367
368 CreateCaret (infoPtr->hwndSelf, NULL, 1, infoPtr->nHeight - 2);
369
370 SetCaretPos (infoPtr->CaretPos, 3);
371
372 ShowCaret (infoPtr->hwndSelf);
373
374
375 return 0;
376}
377
378
379inline static LRESULT
380HOTKEY_SetFont (HOTKEY_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
381{
382 TEXTMETRICW tm;
383 HDC hdc;
384 HFONT hOldFont = 0;
385
386 infoPtr->hFont = (HFONT)wParam;
387
388 hdc = GetDC (infoPtr->hwndSelf);
389 if (infoPtr->hFont)
390 hOldFont = SelectObject (hdc, infoPtr->hFont);
391
392 GetTextMetricsW (hdc, &tm);
393 infoPtr->nHeight = tm.tmHeight;
394
395 if (infoPtr->hFont)
396 SelectObject (hdc, hOldFont);
397 ReleaseDC (infoPtr->hwndSelf, hdc);
398
399 if (LOWORD(lParam))
400 InvalidateRect (infoPtr->hwndSelf, NULL, TRUE);
401
402 return 0;
403}
404
405static LRESULT WINAPI
406HOTKEY_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
407{
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)
413 {
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;
422
423/* case WM_CHAR: */
424
425 case WM_CREATE:
426 return HOTKEY_Create (hwnd, wParam, lParam);
427
428 case WM_DESTROY:
429 return HOTKEY_Destroy (infoPtr, wParam, lParam);
430
431 case WM_ERASEBKGND:
432 return HOTKEY_EraseBackground (infoPtr, wParam, lParam);
433
434 case WM_GETDLGCODE:
435 return DLGC_WANTCHARS | DLGC_WANTARROWS;
436
437 case WM_GETFONT:
438 return HOTKEY_GetFont (infoPtr, wParam, lParam);
439
440 case WM_KEYDOWN:
441 case WM_SYSKEYDOWN:
442 return HOTKEY_KeyDown (infoPtr, wParam, lParam);
443
444 case WM_KEYUP:
445 case WM_SYSKEYUP:
446 return HOTKEY_KeyUp (infoPtr, wParam, lParam);
447
448 case WM_KILLFOCUS:
449 return HOTKEY_KillFocus (infoPtr, wParam, lParam);
450
451 case WM_LBUTTONDOWN:
452 return HOTKEY_LButtonDown (infoPtr, wParam, lParam);
453
454 case WM_NCCREATE:
455 return HOTKEY_NCCreate (infoPtr, wParam, lParam);
456
457 case WM_PAINT:
458 HOTKEY_Paint(infoPtr, (HDC)wParam);
459 return 0;
460
461 case WM_SETFOCUS:
462 return HOTKEY_SetFocus (infoPtr, wParam, lParam);
463
464 case WM_SETFONT:
465 return HOTKEY_SetFont (infoPtr, wParam, lParam);
466
467/* case WM_SYSCHAR: */
468
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);
474 }
475 return 0;
476}
477
478
479void
480HOTKEY_Register (void)
481{
482 WNDCLASSW wndClass;
483
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;
492
493 RegisterClassW (&wndClass);
494}
495
496
497void
498HOTKEY_Unregister (void)
499{
500 UnregisterClassW (HOTKEY_CLASSW, NULL);
501}
Note: See TracBrowser for help on using the repository browser.