xref: /reactos/dll/win32/comctl32/hotkey.c (revision 0707475f)
1 /*
2  * Hotkey control
3  *
4  * Copyright 1998, 1999 Eric Kohl
5  * Copyright 2002 Gyorgy 'Nog' Jeney
6  * Copyright 2004 Robert Shearman
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  *
22  * This code was audited for completeness against the documented features
23  * of Comctl32.dll version 6.0 on Sep. 21, 2004, by Robert Shearman.
24  *
25  * Unless otherwise noted, we believe this code to be complete, as per
26  * the specification mentioned above.
27  * If you discover missing features or bugs please note them below.
28  *
29  */
30 
31 #include <stdarg.h>
32 #include <string.h>
33 #include "windef.h"
34 #include "winbase.h"
35 #include "wingdi.h"
36 #include "winuser.h"
37 #include "winnls.h"
38 #include "commctrl.h"
39 #include "comctl32.h"
40 #include "wine/debug.h"
41 #include "wine/heap.h"
42 
43 WINE_DEFAULT_DEBUG_CHANNEL(hotkey);
44 
45 typedef struct tagHOTKEY_INFO
46 {
47     HWND  hwndSelf;
48     HWND  hwndNotify;
49     HFONT hFont;
50     BOOL  bFocus;
51     INT   nHeight;
52     WORD  HotKey;
53     WORD  InvComb;
54     WORD  InvMod;
55     BYTE  CurrMod;
56     INT   CaretPos;
57     DWORD ScanCode;
58     WCHAR strNone[15]; /* hope it's long enough ... */
59 } HOTKEY_INFO;
60 
61 static const WCHAR HOTKEY_plussep[] = { ' ', '+', ' ' };
62 static LRESULT HOTKEY_SetFont (HOTKEY_INFO *infoPtr, HFONT hFont, BOOL redraw);
63 
64 #define IsOnlySet(flags) (infoPtr->CurrMod == (flags))
65 
66 static BOOL
HOTKEY_IsCombInv(const HOTKEY_INFO * infoPtr)67 HOTKEY_IsCombInv(const HOTKEY_INFO *infoPtr)
68 {
69     TRACE("(infoPtr=%p)\n", infoPtr);
70     if((infoPtr->InvComb & HKCOMB_NONE) && !infoPtr->CurrMod)
71 	return TRUE;
72     if((infoPtr->InvComb & HKCOMB_S) && IsOnlySet(HOTKEYF_SHIFT))
73 	return TRUE;
74     if((infoPtr->InvComb & HKCOMB_C) && IsOnlySet(HOTKEYF_CONTROL))
75 	return TRUE;
76     if((infoPtr->InvComb & HKCOMB_A) && IsOnlySet(HOTKEYF_ALT))
77 	return TRUE;
78     if((infoPtr->InvComb & HKCOMB_SC) &&
79        IsOnlySet(HOTKEYF_SHIFT | HOTKEYF_CONTROL))
80 	return TRUE;
81     if((infoPtr->InvComb & HKCOMB_SA) && IsOnlySet(HOTKEYF_SHIFT | HOTKEYF_ALT))
82 	return TRUE;
83     if((infoPtr->InvComb & HKCOMB_CA) &&
84        IsOnlySet(HOTKEYF_CONTROL | HOTKEYF_ALT))
85 	return TRUE;
86     if((infoPtr->InvComb & HKCOMB_SCA) &&
87        IsOnlySet(HOTKEYF_SHIFT | HOTKEYF_CONTROL | HOTKEYF_ALT))
88 	return TRUE;
89 
90     TRACE("() Modifiers are valid\n");
91     return FALSE;
92 }
93 #undef IsOnlySet
94 
95 static void
HOTKEY_DrawHotKey(HOTKEY_INFO * infoPtr,HDC hdc,LPCWSTR KeyName,WORD NameLen)96 HOTKEY_DrawHotKey(HOTKEY_INFO *infoPtr, HDC hdc, LPCWSTR KeyName, WORD NameLen)
97 {
98     SIZE TextSize;
99     INT nXStart, nYStart;
100     COLORREF clrOldText, clrOldBk;
101     HFONT hFontOld;
102 
103     /* Make a gap from the frame */
104     nXStart = GetSystemMetrics(SM_CXBORDER);
105     nYStart = GetSystemMetrics(SM_CYBORDER);
106 
107     hFontOld = SelectObject(hdc, infoPtr->hFont);
108     if (GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE) & WS_DISABLED)
109     {
110         clrOldText = SetTextColor(hdc, comctl32_color.clrGrayText);
111         clrOldBk = SetBkColor(hdc, comctl32_color.clrBtnFace);
112     }
113     else
114     {
115         clrOldText = SetTextColor(hdc, comctl32_color.clrWindowText);
116         clrOldBk = SetBkColor(hdc, comctl32_color.clrWindow);
117     }
118 
119     TextOutW(hdc, nXStart, nYStart, KeyName, NameLen);
120 
121     /* Get the text width for the caret */
122     GetTextExtentPoint32W(hdc, KeyName, NameLen, &TextSize);
123     infoPtr->CaretPos = nXStart + TextSize.cx;
124 
125     SetBkColor(hdc, clrOldBk);
126     SetTextColor(hdc, clrOldText);
127     SelectObject(hdc, hFontOld);
128 
129     /* position the caret */
130     SetCaretPos(infoPtr->CaretPos, nYStart);
131 }
132 
133 /* Draw the names of the keys in the control */
134 static void
HOTKEY_Refresh(HOTKEY_INFO * infoPtr,HDC hdc)135 HOTKEY_Refresh(HOTKEY_INFO *infoPtr, HDC hdc)
136 {
137     WCHAR KeyName[64];
138     WORD NameLen = 0;
139     BYTE Modifier;
140 
141     TRACE("(infoPtr=%p hdc=%p)\n", infoPtr, hdc);
142 
143     if(!infoPtr->CurrMod && !infoPtr->HotKey) {
144 	HOTKEY_DrawHotKey (infoPtr, hdc, infoPtr->strNone, lstrlenW(infoPtr->strNone));
145 	return;
146     }
147 
148     if(infoPtr->HotKey)
149 	Modifier = HIBYTE(infoPtr->HotKey);
150     else if(HOTKEY_IsCombInv(infoPtr))
151 	Modifier = infoPtr->InvMod;
152     else
153 	Modifier = infoPtr->CurrMod;
154 
155     if(Modifier & HOTKEYF_CONTROL) {
156 	GetKeyNameTextW(MAKELPARAM(0, MapVirtualKeyW(VK_CONTROL, 0)),
157 	                          KeyName, 64);
158         NameLen = lstrlenW(KeyName);
159 	memcpy(&KeyName[NameLen], HOTKEY_plussep, sizeof(HOTKEY_plussep));
160 	NameLen += 3;
161     }
162     if(Modifier & HOTKEYF_SHIFT) {
163 	GetKeyNameTextW(MAKELPARAM(0, MapVirtualKeyW(VK_SHIFT, 0)),
164 	                           &KeyName[NameLen], 64 - NameLen);
165 	NameLen = lstrlenW(KeyName);
166 	memcpy(&KeyName[NameLen], HOTKEY_plussep, sizeof(HOTKEY_plussep));
167 	NameLen += 3;
168     }
169     if(Modifier & HOTKEYF_ALT) {
170 	GetKeyNameTextW(MAKELPARAM(0, MapVirtualKeyW(VK_MENU, 0)),
171 	                           &KeyName[NameLen], 64 - NameLen);
172 	NameLen = lstrlenW(KeyName);
173 	memcpy(&KeyName[NameLen], HOTKEY_plussep, sizeof(HOTKEY_plussep));
174 	NameLen += 3;
175     }
176 
177     if(infoPtr->HotKey) {
178 	GetKeyNameTextW(infoPtr->ScanCode, &KeyName[NameLen], 64 - NameLen);
179 	NameLen = lstrlenW(KeyName);
180     }
181     else
182 	KeyName[NameLen] = 0;
183 
184     HOTKEY_DrawHotKey (infoPtr, hdc, KeyName, NameLen);
185 }
186 
187 static void
HOTKEY_Paint(HOTKEY_INFO * infoPtr,HDC hdc)188 HOTKEY_Paint(HOTKEY_INFO *infoPtr, HDC hdc)
189 {
190     if (hdc)
191 	HOTKEY_Refresh(infoPtr, hdc);
192     else {
193 	PAINTSTRUCT ps;
194 	hdc = BeginPaint (infoPtr->hwndSelf, &ps);
195 	HOTKEY_Refresh (infoPtr, hdc);
196 	EndPaint (infoPtr->hwndSelf, &ps);
197     }
198 }
199 
200 static LRESULT
HOTKEY_GetHotKey(const HOTKEY_INFO * infoPtr)201 HOTKEY_GetHotKey(const HOTKEY_INFO *infoPtr)
202 {
203     TRACE("(infoPtr=%p) Modifiers: 0x%x, Virtual Key: %d\n", infoPtr,
204           HIBYTE(infoPtr->HotKey), LOBYTE(infoPtr->HotKey));
205     return (LRESULT)infoPtr->HotKey;
206 }
207 
208 static void
HOTKEY_SetHotKey(HOTKEY_INFO * infoPtr,WORD hotKey)209 HOTKEY_SetHotKey(HOTKEY_INFO *infoPtr, WORD hotKey)
210 {
211     infoPtr->HotKey = hotKey;
212     infoPtr->ScanCode =
213         MAKELPARAM(0, MapVirtualKeyW(LOBYTE(infoPtr->HotKey), 0));
214     TRACE("(infoPtr=%p hotKey=%x) Modifiers: 0x%x, Virtual Key: %d\n", infoPtr,
215           hotKey, HIBYTE(infoPtr->HotKey), LOBYTE(infoPtr->HotKey));
216     InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
217 }
218 
219 static void
HOTKEY_SetRules(HOTKEY_INFO * infoPtr,WORD invComb,WORD invMod)220 HOTKEY_SetRules(HOTKEY_INFO *infoPtr, WORD invComb, WORD invMod)
221 {
222     infoPtr->InvComb = invComb;
223     infoPtr->InvMod = invMod;
224     TRACE("(infoPtr=%p) Invalid Modifiers: 0x%x, If Invalid: 0x%x\n", infoPtr,
225           infoPtr->InvComb, infoPtr->InvMod);
226 }
227 
228 
229 static LRESULT
HOTKEY_Create(HOTKEY_INFO * infoPtr,const CREATESTRUCTW * lpcs)230 HOTKEY_Create (HOTKEY_INFO *infoPtr, const CREATESTRUCTW *lpcs)
231 {
232     infoPtr->hwndNotify = lpcs->hwndParent;
233 
234     HOTKEY_SetFont(infoPtr, GetStockObject(SYSTEM_FONT), 0);
235 
236     return 0;
237 }
238 
239 
240 static LRESULT
HOTKEY_Destroy(HOTKEY_INFO * infoPtr)241 HOTKEY_Destroy (HOTKEY_INFO *infoPtr)
242 {
243     /* free hotkey info data */
244     SetWindowLongPtrW (infoPtr->hwndSelf, 0, 0);
245     heap_free (infoPtr);
246     return 0;
247 }
248 
249 
250 static LRESULT
HOTKEY_EraseBackground(const HOTKEY_INFO * infoPtr,HDC hdc)251 HOTKEY_EraseBackground (const HOTKEY_INFO *infoPtr, HDC hdc)
252 {
253     HBRUSH hBrush, hSolidBrush = NULL;
254     RECT   rc;
255 
256     if (GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE) & WS_DISABLED)
257         hBrush = hSolidBrush = CreateSolidBrush(comctl32_color.clrBtnFace);
258     else
259     {
260         hBrush = (HBRUSH)SendMessageW(infoPtr->hwndNotify, WM_CTLCOLOREDIT,
261                                       (WPARAM)hdc, (LPARAM)infoPtr->hwndSelf);
262         if (!hBrush)
263             hBrush = hSolidBrush = CreateSolidBrush(comctl32_color.clrWindow);
264     }
265 
266     GetClientRect (infoPtr->hwndSelf, &rc);
267 
268     FillRect (hdc, &rc, hBrush);
269 
270     if (hSolidBrush)
271         DeleteObject(hSolidBrush);
272 
273     return -1;
274 }
275 
276 
277 static inline LRESULT
HOTKEY_GetFont(const HOTKEY_INFO * infoPtr)278 HOTKEY_GetFont (const HOTKEY_INFO *infoPtr)
279 {
280     return (LRESULT)infoPtr->hFont;
281 }
282 
283 static LRESULT
HOTKEY_KeyDown(HOTKEY_INFO * infoPtr,DWORD key,DWORD flags)284 HOTKEY_KeyDown (HOTKEY_INFO *infoPtr, DWORD key, DWORD flags)
285 {
286     WORD wOldHotKey;
287     BYTE bOldMod;
288 
289     if (GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE) & WS_DISABLED)
290         return 0;
291 
292     TRACE("() Key: %d\n", key);
293 
294     wOldHotKey = infoPtr->HotKey;
295     bOldMod = infoPtr->CurrMod;
296 
297     /* If any key is Pressed, we have to reset the hotkey in the control */
298     infoPtr->HotKey = 0;
299 
300     switch (key)
301     {
302 	case VK_RETURN:
303 	case VK_TAB:
304 	case VK_SPACE:
305 	case VK_DELETE:
306 	case VK_ESCAPE:
307 	case VK_BACK:
308 	    InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
309 	    return DefWindowProcW (infoPtr->hwndSelf, WM_KEYDOWN, key, flags);
310 
311 	case VK_SHIFT:
312 	    infoPtr->CurrMod |= HOTKEYF_SHIFT;
313 	    break;
314 	case VK_CONTROL:
315 	    infoPtr->CurrMod |= HOTKEYF_CONTROL;
316 	    break;
317 	case VK_MENU:
318 	    infoPtr->CurrMod |= HOTKEYF_ALT;
319 	    break;
320 
321 	default:
322 	    if(HOTKEY_IsCombInv(infoPtr))
323 	        infoPtr->HotKey = MAKEWORD(key, infoPtr->InvMod);
324 	    else
325 	        infoPtr->HotKey = MAKEWORD(key, infoPtr->CurrMod);
326 	    infoPtr->ScanCode = flags;
327 	    break;
328     }
329 
330     if ((wOldHotKey != infoPtr->HotKey) || (bOldMod != infoPtr->CurrMod))
331     {
332         InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
333 
334         /* send EN_CHANGE notification */
335         SendMessageW(infoPtr->hwndNotify, WM_COMMAND,
336             MAKEWPARAM(GetDlgCtrlID(infoPtr->hwndSelf), EN_CHANGE),
337             (LPARAM)infoPtr->hwndSelf);
338     }
339 
340     return 0;
341 }
342 
343 
344 static LRESULT
HOTKEY_KeyUp(HOTKEY_INFO * infoPtr,DWORD key)345 HOTKEY_KeyUp (HOTKEY_INFO *infoPtr, DWORD key)
346 {
347     BYTE bOldMod;
348 
349     if (GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE) & WS_DISABLED)
350         return 0;
351 
352     TRACE("() Key: %d\n", key);
353 
354     bOldMod = infoPtr->CurrMod;
355 
356     switch (key)
357     {
358 	case VK_SHIFT:
359 	    infoPtr->CurrMod &= ~HOTKEYF_SHIFT;
360 	    break;
361 	case VK_CONTROL:
362 	    infoPtr->CurrMod &= ~HOTKEYF_CONTROL;
363 	    break;
364 	case VK_MENU:
365 	    infoPtr->CurrMod &= ~HOTKEYF_ALT;
366 	    break;
367 	default:
368 	    return 1;
369     }
370 
371     if (bOldMod != infoPtr->CurrMod)
372     {
373         InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
374 
375         /* send EN_CHANGE notification */
376         SendMessageW(infoPtr->hwndNotify, WM_COMMAND,
377             MAKEWPARAM(GetDlgCtrlID(infoPtr->hwndSelf), EN_CHANGE),
378             (LPARAM)infoPtr->hwndSelf);
379     }
380 
381     return 0;
382 }
383 
384 
385 static LRESULT
HOTKEY_KillFocus(HOTKEY_INFO * infoPtr)386 HOTKEY_KillFocus (HOTKEY_INFO *infoPtr)
387 {
388     infoPtr->bFocus = FALSE;
389     DestroyCaret ();
390 
391     return 0;
392 }
393 
394 
395 static LRESULT
HOTKEY_LButtonDown(const HOTKEY_INFO * infoPtr)396 HOTKEY_LButtonDown (const HOTKEY_INFO *infoPtr)
397 {
398     if (!(GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE) & WS_DISABLED))
399         SetFocus (infoPtr->hwndSelf);
400 
401     return 0;
402 }
403 
404 
405 static inline LRESULT
HOTKEY_NCCreate(HWND hwnd,const CREATESTRUCTW * lpcs)406 HOTKEY_NCCreate (HWND hwnd, const CREATESTRUCTW *lpcs)
407 {
408     HOTKEY_INFO *infoPtr;
409     DWORD dwExStyle = GetWindowLongW (hwnd, GWL_EXSTYLE);
410     SetWindowLongW (hwnd, GWL_EXSTYLE,
411                     dwExStyle | WS_EX_CLIENTEDGE);
412 
413     /* allocate memory for info structure */
414     infoPtr = heap_alloc_zero (sizeof(*infoPtr));
415     SetWindowLongPtrW(hwnd, 0, (DWORD_PTR)infoPtr);
416 
417     /* initialize info structure */
418     infoPtr->HotKey = infoPtr->InvComb = infoPtr->InvMod = infoPtr->CurrMod = 0;
419     infoPtr->CaretPos = GetSystemMetrics(SM_CXBORDER);
420     infoPtr->hwndSelf = hwnd;
421     LoadStringW(COMCTL32_hModule, HKY_NONE, infoPtr->strNone, 15);
422 
423     return DefWindowProcW (infoPtr->hwndSelf, WM_NCCREATE, 0, (LPARAM)lpcs);
424 }
425 
426 static LRESULT
HOTKEY_SetFocus(HOTKEY_INFO * infoPtr)427 HOTKEY_SetFocus (HOTKEY_INFO *infoPtr)
428 {
429     infoPtr->bFocus = TRUE;
430 
431     CreateCaret (infoPtr->hwndSelf, NULL, 1, infoPtr->nHeight);
432     SetCaretPos (infoPtr->CaretPos, GetSystemMetrics(SM_CYBORDER));
433     ShowCaret (infoPtr->hwndSelf);
434 
435     return 0;
436 }
437 
438 
439 static LRESULT
HOTKEY_SetFont(HOTKEY_INFO * infoPtr,HFONT hFont,BOOL redraw)440 HOTKEY_SetFont (HOTKEY_INFO *infoPtr, HFONT hFont, BOOL redraw)
441 {
442     TEXTMETRICW tm;
443     HDC hdc;
444     HFONT hOldFont = 0;
445 
446     infoPtr->hFont = hFont;
447 
448     hdc = GetDC (infoPtr->hwndSelf);
449     if (infoPtr->hFont)
450 	hOldFont = SelectObject (hdc, infoPtr->hFont);
451 
452     GetTextMetricsW (hdc, &tm);
453     infoPtr->nHeight = tm.tmHeight;
454 
455     if (infoPtr->hFont)
456 	SelectObject (hdc, hOldFont);
457     ReleaseDC (infoPtr->hwndSelf, hdc);
458 
459     if (redraw)
460 	InvalidateRect (infoPtr->hwndSelf, NULL, TRUE);
461 
462     return 0;
463 }
464 
465 static LRESULT WINAPI
HOTKEY_WindowProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)466 HOTKEY_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
467 {
468     HOTKEY_INFO *infoPtr = (HOTKEY_INFO *)GetWindowLongPtrW (hwnd, 0);
469     TRACE("hwnd=%p msg=%x wparam=%lx lparam=%lx\n", hwnd, uMsg, wParam, lParam);
470     if (!infoPtr && (uMsg != WM_NCCREATE))
471         return DefWindowProcW (hwnd, uMsg, wParam, lParam);
472     switch (uMsg)
473     {
474 	case HKM_GETHOTKEY:
475 	    return HOTKEY_GetHotKey (infoPtr);
476 	case HKM_SETHOTKEY:
477 	    HOTKEY_SetHotKey (infoPtr, (WORD)wParam);
478 	    break;
479 	case HKM_SETRULES:
480             HOTKEY_SetRules (infoPtr, (WORD)wParam, (WORD)lParam);
481 	    break;
482 
483 	case WM_CHAR:
484 	case WM_SYSCHAR:
485 	    return HOTKEY_KeyDown (infoPtr, MapVirtualKeyW(LOBYTE(HIWORD(lParam)), 1), lParam);
486 
487 	case WM_CREATE:
488 	    return HOTKEY_Create (infoPtr, (LPCREATESTRUCTW)lParam);
489 
490 	case WM_DESTROY:
491 	    return HOTKEY_Destroy (infoPtr);
492 
493 	case WM_ERASEBKGND:
494 	    return HOTKEY_EraseBackground (infoPtr, (HDC)wParam);
495 
496 	case WM_GETDLGCODE:
497 	    return DLGC_WANTCHARS | DLGC_WANTARROWS;
498 
499 	case WM_GETFONT:
500 	    return HOTKEY_GetFont (infoPtr);
501 
502 	case WM_KEYDOWN:
503 	case WM_SYSKEYDOWN:
504 	    return HOTKEY_KeyDown (infoPtr, wParam, lParam);
505 
506 	case WM_KEYUP:
507 	case WM_SYSKEYUP:
508 	    return HOTKEY_KeyUp (infoPtr, wParam);
509 
510 	case WM_KILLFOCUS:
511 	    return HOTKEY_KillFocus (infoPtr);
512 
513 	case WM_LBUTTONDOWN:
514 	    return HOTKEY_LButtonDown (infoPtr);
515 
516 	case WM_NCCREATE:
517 	    return HOTKEY_NCCreate (hwnd, (LPCREATESTRUCTW)lParam);
518 
519 	case WM_PRINTCLIENT:
520 	case WM_PAINT:
521 	    HOTKEY_Paint(infoPtr, (HDC)wParam);
522 	    return 0;
523 
524 	case WM_SETFOCUS:
525 	    return HOTKEY_SetFocus (infoPtr);
526 
527 	case WM_SETFONT:
528 	    return HOTKEY_SetFont (infoPtr, (HFONT)wParam, LOWORD(lParam));
529 
530 	default:
531 	    if ((uMsg >= WM_USER) && (uMsg < WM_APP) && !COMCTL32_IsReflectedMessage(uMsg))
532 		ERR("unknown msg %04x wp=%08lx lp=%08lx\n",
533 		     uMsg, wParam, lParam);
534 	    return DefWindowProcW (hwnd, uMsg, wParam, lParam);
535     }
536     return 0;
537 }
538 
539 
540 void
HOTKEY_Register(void)541 HOTKEY_Register (void)
542 {
543     WNDCLASSW wndClass;
544 
545     ZeroMemory (&wndClass, sizeof(WNDCLASSW));
546     wndClass.style         = CS_GLOBALCLASS;
547     wndClass.lpfnWndProc   = HOTKEY_WindowProc;
548     wndClass.cbClsExtra    = 0;
549     wndClass.cbWndExtra    = sizeof(HOTKEY_INFO *);
550     wndClass.hCursor       = 0;
551     wndClass.hbrBackground = 0;
552     wndClass.lpszClassName = HOTKEY_CLASSW;
553 
554     RegisterClassW (&wndClass);
555 }
556 
557 
558 void
HOTKEY_Unregister(void)559 HOTKEY_Unregister (void)
560 {
561     UnregisterClassW (HOTKEY_CLASSW, NULL);
562 }
563