[User32|Win32k]
[reactos.git] / reactos / subsystems / win32 / win32k / ntuser / hotkey.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 2003 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 /*
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS kernel
22 * PURPOSE: HotKey support
23 * FILE: subsys/win32k/ntuser/hotkey.c
24 * PROGRAMER: Eric Kohl
25 * REVISION HISTORY:
26 * 02-11-2003 EK Created
27 */
28
29
30
31 /*
32
33 FIXME: Hotkey notifications are triggered by keyboard input (physical or programatically)
34 and since only desktops on WinSta0 can recieve input in seems very wrong to allow
35 windows/threads on destops not belonging to WinSta0 to set hotkeys (recieve notifications).
36
37 -Gunnar
38 */
39
40
41 /* INCLUDES ******************************************************************/
42
43 #include <win32k.h>
44
45 #define NDEBUG
46 #include <debug.h>
47
48 /* GLOBALS *******************************************************************/
49
50 LIST_ENTRY gHotkeyList;
51
52 /* FUNCTIONS *****************************************************************/
53
54 INIT_FUNCTION
55 NTSTATUS
56 NTAPI
57 InitHotkeyImpl(VOID)
58 {
59 InitializeListHead(&gHotkeyList);
60
61 return STATUS_SUCCESS;
62 }
63
64 #if 0 //not used
65 NTSTATUS FASTCALL
66 CleanupHotKeys(VOID)
67 {
68
69 return STATUS_SUCCESS;
70 }
71 #endif
72
73 BOOL FASTCALL
74 GetHotKey (UINT fsModifiers,
75 UINT vk,
76 struct _ETHREAD **Thread,
77 HWND *hWnd,
78 int *id)
79 {
80 PHOT_KEY_ITEM HotKeyItem;
81
82 LIST_FOR_EACH(HotKeyItem, &gHotkeyList, HOT_KEY_ITEM, ListEntry)
83 {
84 if (HotKeyItem->fsModifiers == fsModifiers &&
85 HotKeyItem->vk == vk)
86 {
87 if (Thread != NULL)
88 *Thread = HotKeyItem->Thread;
89
90 if (hWnd != NULL)
91 *hWnd = HotKeyItem->hWnd;
92
93 if (id != NULL)
94 *id = HotKeyItem->id;
95
96 return TRUE;
97 }
98 }
99
100 return FALSE;
101 }
102
103 VOID FASTCALL
104 UnregisterWindowHotKeys(PWND Window)
105 {
106 PHOT_KEY_ITEM HotKeyItem, tmp;
107
108 LIST_FOR_EACH_SAFE(HotKeyItem, tmp, &gHotkeyList, HOT_KEY_ITEM, ListEntry)
109 {
110 if (HotKeyItem->hWnd == Window->head.h)
111 {
112 RemoveEntryList (&HotKeyItem->ListEntry);
113 ExFreePool (HotKeyItem);
114 }
115 }
116
117 }
118
119 VOID FASTCALL
120 UnregisterThreadHotKeys(struct _ETHREAD *Thread)
121 {
122 PHOT_KEY_ITEM HotKeyItem, tmp;
123
124 LIST_FOR_EACH_SAFE(HotKeyItem, tmp, &gHotkeyList, HOT_KEY_ITEM, ListEntry)
125 {
126 if (HotKeyItem->Thread == Thread)
127 {
128 RemoveEntryList (&HotKeyItem->ListEntry);
129 ExFreePool (HotKeyItem);
130 }
131 }
132
133 }
134
135 static
136 BOOL FASTCALL
137 IsHotKey (UINT fsModifiers, UINT vk)
138 {
139 PHOT_KEY_ITEM HotKeyItem;
140
141 LIST_FOR_EACH(HotKeyItem, &gHotkeyList, HOT_KEY_ITEM, ListEntry)
142 {
143 if (HotKeyItem->fsModifiers == fsModifiers && HotKeyItem->vk == vk)
144 {
145 return TRUE;
146 }
147 }
148
149 return FALSE;
150 }
151
152 //
153 // Get/SetHotKey message support.
154 //
155 UINT FASTCALL
156 DefWndGetHotKey( HWND hwnd )
157 {
158 PHOT_KEY_ITEM HotKeyItem;
159
160 DPRINT1("DefWndGetHotKey\n");
161
162 if (IsListEmpty(&gHotkeyList)) return 0;
163
164 LIST_FOR_EACH(HotKeyItem, &gHotkeyList, HOT_KEY_ITEM, ListEntry)
165 {
166 if ( HotKeyItem->hWnd == hwnd &&
167 HotKeyItem->id == IDHOT_REACTOS )
168 {
169 return MAKELONG(HotKeyItem->vk, HotKeyItem->fsModifiers);
170 }
171 }
172 return 0;
173 }
174
175 INT FASTCALL
176 DefWndSetHotKey( PWND pWnd, WPARAM wParam )
177 {
178 UINT fsModifiers, vk;
179 PHOT_KEY_ITEM HotKeyItem;
180 HWND hWnd;
181 BOOL HaveSameWnd = FALSE;
182 INT Ret = 1;
183
184 DPRINT1("DefWndSetHotKey wParam 0x%x\n", wParam);
185
186 // A hot key cannot be associated with a child window.
187 if (pWnd->style & WS_CHILD) return 0;
188
189 // VK_ESCAPE, VK_SPACE, and VK_TAB are invalid hot keys.
190 if ( LOWORD(wParam) == VK_ESCAPE ||
191 LOWORD(wParam) == VK_SPACE ||
192 LOWORD(wParam) == VK_TAB ) return -1;
193
194 vk = LOWORD(wParam);
195 fsModifiers = HIWORD(wParam);
196 hWnd = UserHMGetHandle(pWnd);
197
198 if (wParam)
199 {
200 LIST_FOR_EACH(HotKeyItem, &gHotkeyList, HOT_KEY_ITEM, ListEntry)
201 {
202 if ( HotKeyItem->fsModifiers == fsModifiers &&
203 HotKeyItem->vk == vk &&
204 HotKeyItem->id == IDHOT_REACTOS )
205 {
206 if (HotKeyItem->hWnd != hWnd)
207 Ret = 2; // Another window already has the same hot key.
208 break;
209 }
210 }
211 }
212
213 LIST_FOR_EACH(HotKeyItem, &gHotkeyList, HOT_KEY_ITEM, ListEntry)
214 {
215 if ( HotKeyItem->hWnd == hWnd &&
216 HotKeyItem->id == IDHOT_REACTOS )
217 {
218 HaveSameWnd = TRUE;
219 break;
220 }
221 }
222
223 if (HaveSameWnd)
224 {
225 if (wParam == 0)
226 { // Setting wParam to NULL removes the hot key associated with a window.
227 UnregisterWindowHotKeys(pWnd);
228 }
229 else
230 { /* A window can only have one hot key. If the window already has a hot key
231 associated with it, the new hot key replaces the old one. */
232 HotKeyItem->fsModifiers = fsModifiers;
233 HotKeyItem->vk = vk;
234 }
235 }
236 else //
237 {
238 if (wParam == 0)
239 return 1; // Do nothing, exit.
240
241 HotKeyItem = ExAllocatePoolWithTag (PagedPool, sizeof(HOT_KEY_ITEM), USERTAG_HOTKEY);
242 if (HotKeyItem == NULL)
243 {
244 return 0;
245 }
246
247 HotKeyItem->Thread = pWnd->head.pti->pEThread;
248 HotKeyItem->hWnd = hWnd;
249 HotKeyItem->id = IDHOT_REACTOS; // Don't care, these hot keys are unrelated to the hot keys set by RegisterHotKey.
250 HotKeyItem->fsModifiers = fsModifiers;
251 HotKeyItem->vk = vk;
252
253 InsertHeadList (&gHotkeyList, &HotKeyItem->ListEntry);
254 }
255 return Ret;
256 }
257
258 /* SYSCALLS *****************************************************************/
259
260
261 BOOL APIENTRY
262 NtUserRegisterHotKey(HWND hWnd,
263 int id,
264 UINT fsModifiers,
265 UINT vk)
266 {
267 PHOT_KEY_ITEM HotKeyItem;
268 PWND Window;
269 PETHREAD HotKeyThread;
270 DECLARE_RETURN(BOOL);
271
272 DPRINT("Enter NtUserRegisterHotKey\n");
273 UserEnterExclusive();
274
275 if (hWnd == NULL)
276 {
277 HotKeyThread = PsGetCurrentThread();
278 }
279 else
280 {
281 if(!(Window = UserGetWindowObject(hWnd)))
282 {
283 RETURN( FALSE);
284 }
285 HotKeyThread = Window->head.pti->pEThread;
286 }
287
288 /* Check for existing hotkey */
289 if (IsHotKey (fsModifiers, vk))
290 {
291 RETURN( FALSE);
292 }
293
294 HotKeyItem = ExAllocatePoolWithTag (PagedPool, sizeof(HOT_KEY_ITEM), USERTAG_HOTKEY);
295 if (HotKeyItem == NULL)
296 {
297 RETURN( FALSE);
298 }
299
300 HotKeyItem->Thread = HotKeyThread;
301 HotKeyItem->hWnd = hWnd;
302 HotKeyItem->id = id;
303 HotKeyItem->fsModifiers = fsModifiers;
304 HotKeyItem->vk = vk;
305
306 InsertHeadList (&gHotkeyList, &HotKeyItem->ListEntry);
307
308 RETURN( TRUE);
309
310 CLEANUP:
311 DPRINT("Leave NtUserRegisterHotKey, ret=%i\n",_ret_);
312 UserLeave();
313 END_CLEANUP;
314 }
315
316
317 BOOL APIENTRY
318 NtUserUnregisterHotKey(HWND hWnd, int id)
319 {
320 PHOT_KEY_ITEM HotKeyItem;
321 PWND Window;
322 DECLARE_RETURN(BOOL);
323
324 DPRINT("Enter NtUserUnregisterHotKey\n");
325 UserEnterExclusive();
326
327 if(!(Window = UserGetWindowObject(hWnd)))
328 {
329 RETURN( FALSE);
330 }
331
332 LIST_FOR_EACH(HotKeyItem, &gHotkeyList, HOT_KEY_ITEM, ListEntry)
333 {
334 if (HotKeyItem->hWnd == hWnd && HotKeyItem->id == id)
335 {
336 RemoveEntryList (&HotKeyItem->ListEntry);
337 ExFreePoolWithTag(HotKeyItem, USERTAG_HOTKEY);
338
339 RETURN( TRUE);
340 }
341 }
342
343 RETURN( FALSE);
344
345 CLEANUP:
346 DPRINT("Leave NtUserUnregisterHotKey, ret=%i\n",_ret_);
347 UserLeave();
348 END_CLEANUP;
349 }
350
351 /* EOF */