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