Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/dlls/comctl32/hotkey.c
8713 views
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 <stdlib.h>
33
#include <string.h>
34
#include "windef.h"
35
#include "winbase.h"
36
#include "wingdi.h"
37
#include "winuser.h"
38
#include "winnls.h"
39
#include "commctrl.h"
40
#include "comctl32.h"
41
#include "wine/debug.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
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
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
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
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
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
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
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
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
241
HOTKEY_Destroy (HOTKEY_INFO *infoPtr)
242
{
243
/* Free hotkey info data */
244
SetWindowLongPtrW (infoPtr->hwndSelf, 0, 0);
245
Free (infoPtr);
246
return 0;
247
}
248
249
250
static LRESULT
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
278
HOTKEY_GetFont (const HOTKEY_INFO *infoPtr)
279
{
280
return (LRESULT)infoPtr->hFont;
281
}
282
283
static LRESULT
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: %ld\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
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: %ld\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
386
HOTKEY_KillFocus (HOTKEY_INFO *infoPtr)
387
{
388
infoPtr->bFocus = FALSE;
389
DestroyCaret ();
390
391
return 0;
392
}
393
394
395
static LRESULT
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
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 = Alloc(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
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
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
466
HOTKEY_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
467
{
468
HOTKEY_INFO *infoPtr = (HOTKEY_INFO *)GetWindowLongPtrW (hwnd, 0);
469
470
TRACE("hwnd %p, msg %x, wparam %Ix, lparam %Ix\n", hwnd, uMsg, wParam, lParam);
471
472
if (!infoPtr && (uMsg != WM_NCCREATE))
473
return DefWindowProcW (hwnd, uMsg, wParam, lParam);
474
switch (uMsg)
475
{
476
case HKM_GETHOTKEY:
477
return HOTKEY_GetHotKey (infoPtr);
478
case HKM_SETHOTKEY:
479
HOTKEY_SetHotKey (infoPtr, (WORD)wParam);
480
break;
481
case HKM_SETRULES:
482
HOTKEY_SetRules (infoPtr, (WORD)wParam, (WORD)lParam);
483
break;
484
485
case WM_CHAR:
486
case WM_SYSCHAR:
487
return HOTKEY_KeyDown (infoPtr, MapVirtualKeyW(LOBYTE(HIWORD(lParam)), 1), lParam);
488
489
case WM_CREATE:
490
return HOTKEY_Create (infoPtr, (LPCREATESTRUCTW)lParam);
491
492
case WM_DESTROY:
493
return HOTKEY_Destroy (infoPtr);
494
495
case WM_ERASEBKGND:
496
return HOTKEY_EraseBackground (infoPtr, (HDC)wParam);
497
498
case WM_GETDLGCODE:
499
return DLGC_WANTCHARS | DLGC_WANTARROWS;
500
501
case WM_GETOBJECT:
502
if ((LONG)lParam == OBJID_QUERYCLASSNAMEIDX)
503
return 0x10010;
504
return DefWindowProcW (hwnd, uMsg, wParam, lParam);
505
506
case WM_GETFONT:
507
return HOTKEY_GetFont (infoPtr);
508
509
case WM_KEYDOWN:
510
case WM_SYSKEYDOWN:
511
return HOTKEY_KeyDown (infoPtr, wParam, lParam);
512
513
case WM_KEYUP:
514
case WM_SYSKEYUP:
515
return HOTKEY_KeyUp (infoPtr, wParam);
516
517
case WM_KILLFOCUS:
518
return HOTKEY_KillFocus (infoPtr);
519
520
case WM_LBUTTONDOWN:
521
return HOTKEY_LButtonDown (infoPtr);
522
523
case WM_NCCREATE:
524
return HOTKEY_NCCreate (hwnd, (LPCREATESTRUCTW)lParam);
525
526
case WM_NCPAINT:
527
return COMCTL32_NCPaint (hwnd, wParam, lParam, WC_EDITW);
528
529
case WM_PRINTCLIENT:
530
case WM_PAINT:
531
HOTKEY_Paint(infoPtr, (HDC)wParam);
532
return 0;
533
534
case WM_SETFOCUS:
535
return HOTKEY_SetFocus (infoPtr);
536
537
case WM_SETFONT:
538
return HOTKEY_SetFont (infoPtr, (HFONT)wParam, LOWORD(lParam));
539
540
default:
541
if ((uMsg >= WM_USER) && (uMsg < WM_APP) && !COMCTL32_IsReflectedMessage(uMsg))
542
ERR("unknown msg %04x, wp %Ix, lp %Ix\n", uMsg, wParam, lParam);
543
return DefWindowProcW (hwnd, uMsg, wParam, lParam);
544
}
545
return 0;
546
}
547
548
549
void
550
HOTKEY_Register (void)
551
{
552
WNDCLASSW wndClass;
553
554
ZeroMemory (&wndClass, sizeof(WNDCLASSW));
555
wndClass.style = CS_GLOBALCLASS;
556
wndClass.lpfnWndProc = HOTKEY_WindowProc;
557
wndClass.cbClsExtra = 0;
558
wndClass.cbWndExtra = sizeof(HOTKEY_INFO *);
559
wndClass.hCursor = 0;
560
wndClass.hbrBackground = 0;
561
wndClass.lpszClassName = HOTKEY_CLASSW;
562
563
RegisterClassW (&wndClass);
564
}
565
566