Added server_abort_thread to replace SYSDEPS_AbortThread.
[wine/hacks.git] / dlls / comctl32 / hotkey.c
blobdb27bac6277436b1019d769b85417f8081ffbafa
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 HFONT hFont;
42 BOOL bFocus;
43 INT nHeight;
44 WORD HotKey;
45 WORD InvComb;
46 WORD InvMod;
47 BYTE CurrMod;
48 INT CaretPos;
49 DWORD ScanCode;
50 WCHAR strNone[15]; /* hope its long enough ... */
51 } HOTKEY_INFO;
53 #define HOTKEY_GetInfoPtr(hwnd) ((HOTKEY_INFO *)GetWindowLongA (hwnd, 0))
55 static const WCHAR HOTKEY_plussep[] = { ' ', '+', ' ' };
57 #define IsOnlySet(flags) (infoPtr->CurrMod == (flags))
59 static BOOL
60 HOTKEY_IsCombInv(HOTKEY_INFO *infoPtr)
62 TRACE("(infoPtr=%p)\n", infoPtr);
63 if((infoPtr->InvComb & HKCOMB_NONE) && !infoPtr->CurrMod)
64 return TRUE;
65 if((infoPtr->InvComb & HKCOMB_S) && IsOnlySet(HOTKEYF_SHIFT))
66 return TRUE;
67 if((infoPtr->InvComb & HKCOMB_C) && IsOnlySet(HOTKEYF_CONTROL))
68 return TRUE;
69 if((infoPtr->InvComb & HKCOMB_A) && IsOnlySet(HOTKEYF_ALT))
70 return TRUE;
71 if((infoPtr->InvComb & HKCOMB_SC) &&
72 IsOnlySet(HOTKEYF_SHIFT | HOTKEYF_CONTROL))
73 return TRUE;
74 if((infoPtr->InvComb & HKCOMB_SA) && IsOnlySet(HOTKEYF_SHIFT | HOTKEYF_ALT))
75 return TRUE;
76 if((infoPtr->InvComb & HKCOMB_CA) &&
77 IsOnlySet(HOTKEYF_CONTROL | HOTKEYF_ALT))
78 return TRUE;
79 if((infoPtr->InvComb & HKCOMB_SCA) &&
80 IsOnlySet(HOTKEYF_SHIFT | HOTKEYF_CONTROL | HOTKEYF_ALT))
81 return TRUE;
83 TRACE("() Modifiers are valid\n");
84 return FALSE;
86 #undef IsOnlySet
88 static void
89 HOTKEY_DrawHotKey(HOTKEY_INFO *infoPtr, LPCWSTR KeyName, WORD NameLen,
90 LPRECT rc, HDC hdc)
92 SIZE TextSize;
93 DWORD dwExStyle = GetWindowLongW (infoPtr->hwndSelf, GWL_EXSTYLE);
95 /* We have to allow some space for the frame to be drawn */
96 rc->left += 2;
97 rc->top++;
98 DrawTextW(hdc, KeyName, NameLen, rc, DT_LEFT | DT_VCENTER);
99 rc->left -= 2;
100 rc->top--;
101 if(dwExStyle & WS_EX_CLIENTEDGE)
102 DrawEdge(hdc, rc, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
104 /* Get the text size and position the caret accordingly */
105 GetTextExtentPoint32W (hdc, KeyName, NameLen, &TextSize);
106 infoPtr->CaretPos = TextSize.cx + 2;
107 SetCaretPos(infoPtr->CaretPos, 3);
110 /* Draw the names of the keys in the control */
111 static void
112 HOTKEY_Refresh(HOTKEY_INFO *infoPtr, HDC hdc)
114 WCHAR KeyName[sizeof(WCHAR) * 64];
115 WORD NameLen = 0;
116 BYTE Modifier;
117 RECT rc;
119 GetClientRect(infoPtr->hwndSelf, &rc);
121 TRACE("(infoPtr=%p hdc=%p)\n", infoPtr, hdc);
123 if(!infoPtr->CurrMod && !infoPtr->HotKey) {
124 HOTKEY_DrawHotKey (infoPtr, infoPtr->strNone, 4, &rc, hdc);
125 return;
128 if(infoPtr->HotKey)
129 Modifier = HIBYTE(infoPtr->HotKey);
130 else if(HOTKEY_IsCombInv(infoPtr))
131 Modifier = infoPtr->InvMod;
132 else
133 Modifier = infoPtr->CurrMod;
135 if(Modifier & HOTKEYF_CONTROL) {
136 GetKeyNameTextW(MAKELPARAM(0, MapVirtualKeyW(VK_CONTROL, 0)),
137 KeyName, 64);
138 NameLen = lstrlenW(KeyName);
139 memcpy(&KeyName[NameLen], HOTKEY_plussep, sizeof(HOTKEY_plussep));
140 NameLen += 3;
142 if(Modifier & HOTKEYF_SHIFT) {
143 GetKeyNameTextW(MAKELPARAM(0, MapVirtualKeyW(VK_SHIFT, 0)),
144 &KeyName[NameLen], 64 - NameLen);
145 NameLen = lstrlenW(KeyName);
146 memcpy(&KeyName[NameLen], HOTKEY_plussep, sizeof(HOTKEY_plussep));
147 NameLen += 3;
149 if(Modifier & HOTKEYF_ALT) {
150 GetKeyNameTextW(MAKELPARAM(0, MapVirtualKeyW(VK_MENU, 0)),
151 &KeyName[NameLen], 64 - NameLen);
152 NameLen = lstrlenW(KeyName);
153 memcpy(&KeyName[NameLen], HOTKEY_plussep, sizeof(HOTKEY_plussep));
154 NameLen += 3;
157 if(infoPtr->HotKey) {
158 GetKeyNameTextW(infoPtr->ScanCode, &KeyName[NameLen], 64 - NameLen);
159 NameLen = lstrlenW(KeyName);
161 else
162 KeyName[NameLen] = 0;
164 HOTKEY_DrawHotKey (infoPtr, KeyName, NameLen, &rc, hdc);
167 static void
168 HOTKEY_Paint(HOTKEY_INFO *infoPtr, HDC hdc)
170 if (hdc)
171 HOTKEY_Refresh(infoPtr, hdc);
172 else {
173 PAINTSTRUCT ps;
174 hdc = BeginPaint (infoPtr->hwndSelf, &ps);
175 HOTKEY_Refresh (infoPtr, hdc);
176 EndPaint (infoPtr->hwndSelf, &ps);
180 static LRESULT
181 HOTKEY_GetHotKey(HOTKEY_INFO *infoPtr)
183 TRACE("(infoPtr=%p) Modifiers: 0x%x, Virtual Key: %d\n", infoPtr,
184 HIBYTE(infoPtr->HotKey), LOBYTE(infoPtr->HotKey));
185 return (LRESULT)infoPtr->HotKey;
188 static void
189 HOTKEY_SetHotKey(HOTKEY_INFO *infoPtr, WPARAM wParam)
191 infoPtr->HotKey = (WORD)wParam;
192 infoPtr->ScanCode =
193 MAKELPARAM(0, MapVirtualKeyW(LOBYTE(infoPtr->HotKey), 0));
194 TRACE("(infoPtr=%p wParam=%x) Modifiers: 0x%x, Virtual Key: %d\n", infoPtr,
195 wParam, HIBYTE(infoPtr->HotKey), LOBYTE(infoPtr->HotKey));
196 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
199 static void
200 HOTKEY_SetRules(HOTKEY_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
202 infoPtr->InvComb = (WORD)wParam;
203 infoPtr->InvMod = (WORD)lParam;
204 TRACE("(infoPtr=%p) Invalid Modifers: 0x%x, If Invalid: 0x%x\n", infoPtr,
205 infoPtr->InvComb, infoPtr->InvMod);
208 /* << HOTKEY_Char >> */
210 static LRESULT
211 HOTKEY_Create (HWND hwnd, WPARAM wParam, LPARAM lParam)
213 HOTKEY_INFO *infoPtr;
214 TEXTMETRICW tm;
215 HDC hdc;
217 /* allocate memory for info structure */
218 infoPtr = (HOTKEY_INFO *)Alloc (sizeof(HOTKEY_INFO));
219 SetWindowLongW (hwnd, 0, (DWORD)infoPtr);
221 /* initialize info structure */
222 infoPtr->HotKey = infoPtr->InvComb = infoPtr->InvMod = infoPtr->CurrMod = 0;
223 infoPtr->CaretPos = 2;
224 infoPtr->hwndSelf = hwnd;
225 LoadStringW(COMCTL32_hModule, HKY_NONE, infoPtr->strNone, 15);
227 /* get default font height */
228 hdc = GetDC (hwnd);
229 GetTextMetricsW (hdc, &tm);
230 infoPtr->nHeight = tm.tmHeight;
231 ReleaseDC (hwnd, hdc);
233 return 0;
237 static LRESULT
238 HOTKEY_Destroy (HOTKEY_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
240 HWND hwnd = infoPtr->hwndSelf;
241 /* free hotkey info data */
242 Free (infoPtr);
243 SetWindowLongW (hwnd, 0, 0);
244 return 0;
248 static LRESULT
249 HOTKEY_EraseBackground (HOTKEY_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
251 HBRUSH hBrush;
252 RECT rc;
254 hBrush =
255 (HBRUSH)SendMessageW (GetParent (infoPtr->hwndSelf), WM_CTLCOLOREDIT,
256 wParam, (LPARAM)infoPtr->hwndSelf);
257 if (hBrush)
258 hBrush = (HBRUSH)GetStockObject (WHITE_BRUSH);
259 GetClientRect (infoPtr->hwndSelf, &rc);
261 FillRect ((HDC)wParam, &rc, hBrush);
263 return -1;
267 inline static LRESULT
268 HOTKEY_GetFont (HOTKEY_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
270 return (LRESULT)infoPtr->hFont;
273 static LRESULT
274 HOTKEY_KeyDown (HOTKEY_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
276 TRACE("() Key: %d\n", wParam);
277 /* If any key is Pressed, we have to reset the hotkey in the control */
278 infoPtr->HotKey = 0;
280 switch (wParam) {
281 case VK_RETURN:
282 case VK_TAB:
283 case VK_SPACE:
284 case VK_DELETE:
285 case VK_ESCAPE:
286 case VK_BACK:
287 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
288 return DefWindowProcW (infoPtr->hwndSelf, WM_KEYDOWN, wParam,
289 lParam);
291 case VK_SHIFT:
292 infoPtr->CurrMod |= HOTKEYF_SHIFT;
293 break;
294 case VK_CONTROL:
295 infoPtr->CurrMod |= HOTKEYF_CONTROL;
296 break;
297 case VK_MENU:
298 infoPtr->CurrMod |= HOTKEYF_ALT;
299 break;
301 default:
302 if(HOTKEY_IsCombInv(infoPtr))
303 infoPtr->HotKey = MAKEWORD(wParam, infoPtr->InvMod);
304 else
305 infoPtr->HotKey = MAKEWORD(wParam, infoPtr->CurrMod);
306 infoPtr->ScanCode = lParam;
307 break;
310 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
311 return 0;
315 static LRESULT
316 HOTKEY_KeyUp (HOTKEY_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
318 TRACE("() Key: %d\n", wParam);
319 switch (wParam) {
320 case VK_SHIFT:
321 infoPtr->CurrMod &= ~HOTKEYF_SHIFT;
322 break;
323 case VK_CONTROL:
324 infoPtr->CurrMod &= ~HOTKEYF_CONTROL;
325 break;
326 case VK_MENU:
327 infoPtr->CurrMod &= ~HOTKEYF_ALT;
328 break;
329 default:
330 return 1;
333 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
335 return 0;
339 static LRESULT
340 HOTKEY_KillFocus (HOTKEY_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
342 infoPtr->bFocus = FALSE;
343 DestroyCaret ();
345 return 0;
349 static LRESULT
350 HOTKEY_LButtonDown (HOTKEY_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
352 SetFocus (infoPtr->hwndSelf);
354 return 0;
358 inline static LRESULT
359 HOTKEY_NCCreate (HOTKEY_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
361 DWORD dwExStyle = GetWindowLongW (infoPtr->hwndSelf, GWL_EXSTYLE);
362 SetWindowLongW (infoPtr->hwndSelf, GWL_EXSTYLE,
363 dwExStyle | WS_EX_CLIENTEDGE);
364 return DefWindowProcW (infoPtr->hwndSelf, WM_NCCREATE, wParam, lParam);
367 static LRESULT
368 HOTKEY_SetFocus (HOTKEY_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
370 infoPtr->bFocus = TRUE;
373 CreateCaret (infoPtr->hwndSelf, NULL, 1, infoPtr->nHeight - 2);
375 SetCaretPos (infoPtr->CaretPos, 3);
377 ShowCaret (infoPtr->hwndSelf);
380 return 0;
384 inline static LRESULT
385 HOTKEY_SetFont (HOTKEY_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
387 TEXTMETRICW tm;
388 HDC hdc;
389 HFONT hOldFont = 0;
391 infoPtr->hFont = (HFONT)wParam;
393 hdc = GetDC (infoPtr->hwndSelf);
394 if (infoPtr->hFont)
395 hOldFont = SelectObject (hdc, infoPtr->hFont);
397 GetTextMetricsW (hdc, &tm);
398 infoPtr->nHeight = tm.tmHeight;
400 if (infoPtr->hFont)
401 SelectObject (hdc, hOldFont);
402 ReleaseDC (infoPtr->hwndSelf, hdc);
404 if (LOWORD(lParam))
405 InvalidateRect (infoPtr->hwndSelf, NULL, TRUE);
407 return 0;
410 static LRESULT WINAPI
411 HOTKEY_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
413 HOTKEY_INFO *infoPtr = HOTKEY_GetInfoPtr (hwnd);
414 TRACE("hwnd=%p msg=%x wparam=%x lparam=%lx\n", hwnd, uMsg, wParam, lParam);
415 if (!infoPtr && (uMsg != WM_CREATE))
416 return DefWindowProcW (hwnd, uMsg, wParam, lParam);
417 switch (uMsg)
419 case HKM_GETHOTKEY:
420 return HOTKEY_GetHotKey (infoPtr);
421 case HKM_SETHOTKEY:
422 HOTKEY_SetHotKey (infoPtr, wParam);
423 break;
424 case HKM_SETRULES:
425 HOTKEY_SetRules (infoPtr, wParam, lParam);
426 break;
428 /* case WM_CHAR: */
430 case WM_CREATE:
431 return HOTKEY_Create (hwnd, wParam, lParam);
433 case WM_DESTROY:
434 return HOTKEY_Destroy (infoPtr, wParam, lParam);
436 case WM_ERASEBKGND:
437 return HOTKEY_EraseBackground (infoPtr, wParam, lParam);
439 case WM_GETDLGCODE:
440 return DLGC_WANTCHARS | DLGC_WANTARROWS;
442 case WM_GETFONT:
443 return HOTKEY_GetFont (infoPtr, wParam, lParam);
445 case WM_KEYDOWN:
446 case WM_SYSKEYDOWN:
447 return HOTKEY_KeyDown (infoPtr, wParam, lParam);
449 case WM_KEYUP:
450 case WM_SYSKEYUP:
451 return HOTKEY_KeyUp (infoPtr, wParam, lParam);
453 case WM_KILLFOCUS:
454 return HOTKEY_KillFocus (infoPtr, wParam, lParam);
456 case WM_LBUTTONDOWN:
457 return HOTKEY_LButtonDown (infoPtr, wParam, lParam);
459 case WM_NCCREATE:
460 return HOTKEY_NCCreate (infoPtr, wParam, lParam);
462 case WM_PAINT:
463 HOTKEY_Paint(infoPtr, (HDC)wParam);
464 return 0;
466 case WM_SETFOCUS:
467 return HOTKEY_SetFocus (infoPtr, wParam, lParam);
469 case WM_SETFONT:
470 return HOTKEY_SetFont (infoPtr, wParam, lParam);
472 /* case WM_SYSCHAR: */
474 default:
475 if ((uMsg >= WM_USER) && (uMsg < WM_APP))
476 ERR("unknown msg %04x wp=%08x lp=%08lx\n",
477 uMsg, wParam, lParam);
478 return DefWindowProcW (hwnd, uMsg, wParam, lParam);
480 return 0;
484 void
485 HOTKEY_Register (void)
487 WNDCLASSW wndClass;
489 ZeroMemory (&wndClass, sizeof(WNDCLASSW));
490 wndClass.style = CS_GLOBALCLASS;
491 wndClass.lpfnWndProc = (WNDPROC)HOTKEY_WindowProc;
492 wndClass.cbClsExtra = 0;
493 wndClass.cbWndExtra = sizeof(HOTKEY_INFO *);
494 wndClass.hCursor = 0;
495 wndClass.hbrBackground = 0;
496 wndClass.lpszClassName = HOTKEY_CLASSW;
498 RegisterClassW (&wndClass);
502 void
503 HOTKEY_Unregister (void)
505 UnregisterClassW (HOTKEY_CLASSW, NULL);