windows.gaming.input: Avoid leaking IDirectInputEffect reference (Valgrind).
[wine.git] / dlls / win32u / input.c
blobfb9824759b256b2716d5dbd62cbf712628981316
1 /*
2 * USER Input processing
4 * Copyright 1993 Bob Amstadt
5 * Copyright 1993 David Metcalfe
6 * Copyright 1996 Albrecht Kleine
7 * Copyright 1996 Frans van Dorsselaer
8 * Copyright 1997 David Faure
9 * Copyright 1998 Morten Welinder
10 * Copyright 1998 Ulrich Weigand
11 * Copyright 2001 Eric Pouech
12 * Copyright 2002 Alexandre Julliard
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
29 #if 0
30 #pragma makedep unix
31 #endif
33 #include "ntstatus.h"
34 #define WIN32_NO_STATUS
35 #include "win32u_private.h"
36 #include "ntuser_private.h"
37 #include "wine/server.h"
38 #include "wine/debug.h"
39 #include "kbd.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(win);
42 WINE_DECLARE_DEBUG_CHANNEL(keyboard);
44 static const WCHAR keyboard_layouts_keyW[] =
46 '\\','R','e','g','i','s','t','r','y',
47 '\\','M','a','c','h','i','n','e',
48 '\\','S','y','s','t','e','m',
49 '\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t',
50 '\\','C','o','n','t','r','o','l',
51 '\\','K','e','y','b','o','a','r','d',' ','L','a','y','o','u','t','s'
53 static const WCHAR escW[] = {'E','s','c',0};
54 static const WCHAR backspaceW[] = {'B','a','c','k','s','p','a','c','e',0};
55 static const WCHAR tabW[] = {'T','a','b',0};
56 static const WCHAR enterW[] = {'E','n','t','e','r',0};
57 static const WCHAR ctrlW[] = {'C','t','r','l',0};
58 static const WCHAR shiftW[] = {'S','h','i','f','t',0};
59 static const WCHAR right_shiftW[] = {'R','i','g','h','t',' ','S','h','i','f','t',0};
60 static const WCHAR num_mulW[] = {'N','u','m',' ','*',0};
61 static const WCHAR altW[] = {'A','l','t',0};
62 static const WCHAR spaceW[] = {'S','p','a','c','e',0};
63 static const WCHAR caps_lockW[] = {'C','a','p','s',' ','L','o','c','k',0};
64 static const WCHAR f1W[] = {'F','1',0};
65 static const WCHAR f2W[] = {'F','2',0};
66 static const WCHAR f3W[] = {'F','3',0};
67 static const WCHAR f4W[] = {'F','4',0};
68 static const WCHAR f5W[] = {'F','5',0};
69 static const WCHAR f6W[] = {'F','6',0};
70 static const WCHAR f7W[] = {'F','7',0};
71 static const WCHAR f8W[] = {'F','8',0};
72 static const WCHAR f9W[] = {'F','9',0};
73 static const WCHAR f10W[] = {'F','1','0',0};
74 static const WCHAR pauseW[] = {'P','a','u','s','e',0};
75 static const WCHAR scroll_lockW[] = {'S','c','r','o','l','l',' ','L','o','c','k',0};
76 static const WCHAR num_7W[] = {'N','u','m',' ','7',0};
77 static const WCHAR num_8W[] = {'N','u','m',' ','8',0};
78 static const WCHAR num_9W[] = {'N','u','m',' ','9',0};
79 static const WCHAR num_minusW[] = {'N','u','m',' ','-',0};
80 static const WCHAR num_4W[] = {'N','u','m',' ','4',0};
81 static const WCHAR num_5W[] = {'N','u','m',' ','5',0};
82 static const WCHAR num_6W[] = {'N','u','m',' ','6',0};
83 static const WCHAR num_plusW[] = {'N','u','m',' ','+',0};
84 static const WCHAR num_1W[] = {'N','u','m',' ','1',0};
85 static const WCHAR num_2W[] = {'N','u','m',' ','2',0};
86 static const WCHAR num_3W[] = {'N','u','m',' ','3',0};
87 static const WCHAR num_0W[] = {'N','u','m',' ','0',0};
88 static const WCHAR num_delW[] = {'N','u','m',' ','D','e','l',0};
89 static const WCHAR sys_reqW[] = {'S','y','s',' ','R','e','q',0};
90 static const WCHAR f11W[] = {'F','1','1',0};
91 static const WCHAR f12W[] = {'F','1','2',0};
92 static const WCHAR f13W[] = {'F','1','3',0};
93 static const WCHAR f14W[] = {'F','1','4',0};
94 static const WCHAR f15W[] = {'F','1','5',0};
95 static const WCHAR f16W[] = {'F','1','6',0};
96 static const WCHAR f17W[] = {'F','1','7',0};
97 static const WCHAR f18W[] = {'F','1','8',0};
98 static const WCHAR f19W[] = {'F','1','9',0};
99 static const WCHAR f20W[] = {'F','2','0',0};
100 static const WCHAR f21W[] = {'F','2','1',0};
101 static const WCHAR f22W[] = {'F','2','2',0};
102 static const WCHAR f23W[] = {'F','2','3',0};
103 static const WCHAR f24W[] = {'F','2','4',0};
104 static const WCHAR num_enterW[] = {'N','u','m',' ','E','n','t','e','r',0};
105 static const WCHAR right_ctrlW[] = {'R','i','g','h','t',' ','C','t','r','l',0};
106 static const WCHAR num_divW[] = {'N','u','m',' ','/',0};
107 static const WCHAR prnt_scrnW[] = {'P','r','n','t',' ','S','c','r','n',0};
108 static const WCHAR right_altW[] = {'R','i','g','h','t',' ','A','l','t',0};
109 static const WCHAR num_lockW[] = {'N','u','m',' ','L','o','c','k',0};
110 static const WCHAR breakW[] = {'B','r','e','a','k',0};
111 static const WCHAR homeW[] = {'H','o','m','e',0};
112 static const WCHAR upW[] = {'U','p',0};
113 static const WCHAR page_upW[] = {'P','a','g','e',' ','U','p',0};
114 static const WCHAR leftW[] = {'L','e','f','t',0};
115 static const WCHAR rightW[] = {'R','i','g','h','t',0};
116 static const WCHAR endW[] = {'E','n','d',0};
117 static const WCHAR downW[] = {'D','o','w','n',0};
118 static const WCHAR page_downW[] = {'P','a','g','e',' ','D','o','w','n',0};
119 static const WCHAR insertW[] = {'I','n','s','e','r','t',0};
120 static const WCHAR deleteW[] = {'D','e','l','e','t','e',0};
121 static const WCHAR zerozeroW[] = {'<','0','0','>',0};
122 static const WCHAR helpW[] = {'H','e','l','p',0};
123 static const WCHAR left_windowsW[] = {'L','e','f','t',' ','W','i','n','d','o','w','s',0};
124 static const WCHAR right_windowsW[] = {'R','i','g','h','t',' ','W','i','n','d','o','w','s',0};
125 static const WCHAR applicationW[] = {'A','p','p','l','i','c','a','t','i','o','n',0};
127 static const VK_TO_BIT vk_to_bit[] =
129 {.Vk = VK_SHIFT, .ModBits = KBDSHIFT},
130 {.Vk = VK_CONTROL, .ModBits = KBDCTRL},
131 {.Vk = VK_MENU, .ModBits = KBDALT},
132 {0},
135 static const MODIFIERS modifiers =
137 .pVkToBit = (VK_TO_BIT *)vk_to_bit,
138 .wMaxModBits = 7,
139 .ModNumber = {0, 1, 2, 3, 0, 1, 0, 0},
142 static const VK_TO_WCHARS2 vk_to_wchars2[] =
144 {.VirtualKey = VK_OEM_3, .wch = {'`', '~'}},
145 {.VirtualKey = '1', .wch = {'1', '!'}},
146 {.VirtualKey = '3', .wch = {'3', '#'}},
147 {.VirtualKey = '4', .wch = {'4', '$'}},
148 {.VirtualKey = '5', .wch = {'5', '%'}},
149 {.VirtualKey = '7', .wch = {'7', '&'}},
150 {.VirtualKey = '8', .wch = {'8', '*'}},
151 {.VirtualKey = '9', .wch = {'9', '('}},
152 {.VirtualKey = '0', .wch = {'0', ')'}},
153 {.VirtualKey = VK_OEM_PLUS, .wch = {'=', '+'}},
154 {.VirtualKey = 'Q', .wch = {'q', 'Q'}, .Attributes = CAPLOK},
155 {.VirtualKey = 'W', .wch = {'w', 'W'}, .Attributes = CAPLOK},
156 {.VirtualKey = 'E', .wch = {'e', 'E'}, .Attributes = CAPLOK},
157 {.VirtualKey = 'R', .wch = {'r', 'R'}, .Attributes = CAPLOK},
158 {.VirtualKey = 'T', .wch = {'t', 'T'}, .Attributes = CAPLOK},
159 {.VirtualKey = 'Y', .wch = {'y', 'Y'}, .Attributes = CAPLOK},
160 {.VirtualKey = 'U', .wch = {'u', 'U'}, .Attributes = CAPLOK},
161 {.VirtualKey = 'I', .wch = {'i', 'I'}, .Attributes = CAPLOK},
162 {.VirtualKey = 'O', .wch = {'o', 'O'}, .Attributes = CAPLOK},
163 {.VirtualKey = 'P', .wch = {'p', 'P'}, .Attributes = CAPLOK},
164 {.VirtualKey = 'A', .wch = {'a', 'A'}, .Attributes = CAPLOK},
165 {.VirtualKey = 'S', .wch = {'s', 'S'}, .Attributes = CAPLOK},
166 {.VirtualKey = 'D', .wch = {'d', 'D'}, .Attributes = CAPLOK},
167 {.VirtualKey = 'F', .wch = {'f', 'F'}, .Attributes = CAPLOK},
168 {.VirtualKey = 'G', .wch = {'g', 'G'}, .Attributes = CAPLOK},
169 {.VirtualKey = 'H', .wch = {'h', 'H'}, .Attributes = CAPLOK},
170 {.VirtualKey = 'J', .wch = {'j', 'J'}, .Attributes = CAPLOK},
171 {.VirtualKey = 'K', .wch = {'k', 'K'}, .Attributes = CAPLOK},
172 {.VirtualKey = 'L', .wch = {'l', 'L'}, .Attributes = CAPLOK},
173 {.VirtualKey = VK_OEM_1, .wch = {';', ':'}},
174 {.VirtualKey = VK_OEM_7, .wch = {'\'', '\"'}},
175 {.VirtualKey = 'Z', .wch = {'z', 'Z'}, .Attributes = CAPLOK},
176 {.VirtualKey = 'X', .wch = {'x', 'X'}, .Attributes = CAPLOK},
177 {.VirtualKey = 'C', .wch = {'c', 'C'}, .Attributes = CAPLOK},
178 {.VirtualKey = 'V', .wch = {'v', 'V'}, .Attributes = CAPLOK},
179 {.VirtualKey = 'B', .wch = {'b', 'B'}, .Attributes = CAPLOK},
180 {.VirtualKey = 'N', .wch = {'n', 'N'}, .Attributes = CAPLOK},
181 {.VirtualKey = 'M', .wch = {'m', 'M'}, .Attributes = CAPLOK},
182 {.VirtualKey = VK_OEM_COMMA, .wch = {',', '<'}},
183 {.VirtualKey = VK_OEM_PERIOD, .wch = {'.', '>'}},
184 {.VirtualKey = VK_OEM_2, .wch = {'/', '?'}},
185 {.VirtualKey = VK_DECIMAL, .wch = {'.', '.'}},
186 {.VirtualKey = VK_TAB, .wch = {'\t', '\t'}},
187 {.VirtualKey = VK_ADD, .wch = {'+', '+'}},
188 {.VirtualKey = VK_DIVIDE, .wch = {'/', '/'}},
189 {.VirtualKey = VK_MULTIPLY, .wch = {'*', '*'}},
190 {.VirtualKey = VK_SUBTRACT, .wch = {'-', '-'}},
191 {0},
194 static const VK_TO_WCHARS3 vk_to_wchars3[] =
196 {.VirtualKey = VK_OEM_4, .wch = {'[', '{', '\x001b'}},
197 {.VirtualKey = VK_OEM_6, .wch = {']', '}', '\x001d'}},
198 {.VirtualKey = VK_OEM_5, .wch = {'\\', '|', '\x001c'}},
199 {.VirtualKey = VK_OEM_102, .wch = {'\\', '|', '\x001c'}},
200 {.VirtualKey = VK_BACK, .wch = {'\b', '\b', '\x007f'}},
201 {.VirtualKey = VK_ESCAPE, .wch = {'\x001b', '\x001b', '\x001b'}},
202 {.VirtualKey = VK_RETURN, .wch = {'\r', '\r', '\n'}},
203 {.VirtualKey = VK_SPACE, .wch = {' ', ' ', ' '}},
204 {.VirtualKey = VK_CANCEL, .wch = {'\x0003', '\x0003', '\x0003'}},
205 {0},
208 static const VK_TO_WCHARS4 vk_to_wchars4[] =
210 {.VirtualKey = '2', .wch = {'2', '@', WCH_NONE, '\x0000'}},
211 {.VirtualKey = '6', .wch = {'6', '^', WCH_NONE, '\x001e'}},
212 {.VirtualKey = VK_OEM_MINUS, .wch = {'-', '_', WCH_NONE, '\x001f'}},
213 {0},
216 static const VK_TO_WCHARS1 vk_to_wchars1[] =
218 {.VirtualKey = VK_NUMPAD0, .wch = {'0'}},
219 {.VirtualKey = VK_NUMPAD1, .wch = {'1'}},
220 {.VirtualKey = VK_NUMPAD2, .wch = {'2'}},
221 {.VirtualKey = VK_NUMPAD3, .wch = {'3'}},
222 {.VirtualKey = VK_NUMPAD4, .wch = {'4'}},
223 {.VirtualKey = VK_NUMPAD5, .wch = {'5'}},
224 {.VirtualKey = VK_NUMPAD6, .wch = {'6'}},
225 {.VirtualKey = VK_NUMPAD7, .wch = {'7'}},
226 {.VirtualKey = VK_NUMPAD8, .wch = {'8'}},
227 {.VirtualKey = VK_NUMPAD9, .wch = {'9'}},
228 {0},
231 static const VK_TO_WCHAR_TABLE vk_to_wchar_table[] =
233 {.pVkToWchars = (VK_TO_WCHARS1 *)vk_to_wchars3, .nModifications = 3, .cbSize = sizeof(vk_to_wchars3[0])},
234 {.pVkToWchars = (VK_TO_WCHARS1 *)vk_to_wchars4, .nModifications = 4, .cbSize = sizeof(vk_to_wchars4[0])},
235 {.pVkToWchars = (VK_TO_WCHARS1 *)vk_to_wchars2, .nModifications = 2, .cbSize = sizeof(vk_to_wchars2[0])},
236 {.pVkToWchars = (VK_TO_WCHARS1 *)vk_to_wchars1, .nModifications = 1, .cbSize = sizeof(vk_to_wchars1[0])},
237 {0},
240 static const VSC_LPWSTR key_names[] =
242 {.vsc = 0x01, .pwsz = (WCHAR *)escW},
243 {.vsc = 0x0e, .pwsz = (WCHAR *)backspaceW},
244 {.vsc = 0x0f, .pwsz = (WCHAR *)tabW},
245 {.vsc = 0x1c, .pwsz = (WCHAR *)enterW},
246 {.vsc = 0x1d, .pwsz = (WCHAR *)ctrlW},
247 {.vsc = 0x2a, .pwsz = (WCHAR *)shiftW},
248 {.vsc = 0x36, .pwsz = (WCHAR *)right_shiftW},
249 {.vsc = 0x37, .pwsz = (WCHAR *)num_mulW},
250 {.vsc = 0x38, .pwsz = (WCHAR *)altW},
251 {.vsc = 0x39, .pwsz = (WCHAR *)spaceW},
252 {.vsc = 0x3a, .pwsz = (WCHAR *)caps_lockW},
253 {.vsc = 0x3b, .pwsz = (WCHAR *)f1W},
254 {.vsc = 0x3c, .pwsz = (WCHAR *)f2W},
255 {.vsc = 0x3d, .pwsz = (WCHAR *)f3W},
256 {.vsc = 0x3e, .pwsz = (WCHAR *)f4W},
257 {.vsc = 0x3f, .pwsz = (WCHAR *)f5W},
258 {.vsc = 0x40, .pwsz = (WCHAR *)f6W},
259 {.vsc = 0x41, .pwsz = (WCHAR *)f7W},
260 {.vsc = 0x42, .pwsz = (WCHAR *)f8W},
261 {.vsc = 0x43, .pwsz = (WCHAR *)f9W},
262 {.vsc = 0x44, .pwsz = (WCHAR *)f10W},
263 {.vsc = 0x45, .pwsz = (WCHAR *)pauseW},
264 {.vsc = 0x46, .pwsz = (WCHAR *)scroll_lockW},
265 {.vsc = 0x47, .pwsz = (WCHAR *)num_7W},
266 {.vsc = 0x48, .pwsz = (WCHAR *)num_8W},
267 {.vsc = 0x49, .pwsz = (WCHAR *)num_9W},
268 {.vsc = 0x4a, .pwsz = (WCHAR *)num_minusW},
269 {.vsc = 0x4b, .pwsz = (WCHAR *)num_4W},
270 {.vsc = 0x4c, .pwsz = (WCHAR *)num_5W},
271 {.vsc = 0x4d, .pwsz = (WCHAR *)num_6W},
272 {.vsc = 0x4e, .pwsz = (WCHAR *)num_plusW},
273 {.vsc = 0x4f, .pwsz = (WCHAR *)num_1W},
274 {.vsc = 0x50, .pwsz = (WCHAR *)num_2W},
275 {.vsc = 0x51, .pwsz = (WCHAR *)num_3W},
276 {.vsc = 0x52, .pwsz = (WCHAR *)num_0W},
277 {.vsc = 0x53, .pwsz = (WCHAR *)num_delW},
278 {.vsc = 0x54, .pwsz = (WCHAR *)sys_reqW},
279 {.vsc = 0x57, .pwsz = (WCHAR *)f11W},
280 {.vsc = 0x58, .pwsz = (WCHAR *)f12W},
281 {.vsc = 0x7c, .pwsz = (WCHAR *)f13W},
282 {.vsc = 0x7d, .pwsz = (WCHAR *)f14W},
283 {.vsc = 0x7e, .pwsz = (WCHAR *)f15W},
284 {.vsc = 0x7f, .pwsz = (WCHAR *)f16W},
285 {.vsc = 0x80, .pwsz = (WCHAR *)f17W},
286 {.vsc = 0x81, .pwsz = (WCHAR *)f18W},
287 {.vsc = 0x82, .pwsz = (WCHAR *)f19W},
288 {.vsc = 0x83, .pwsz = (WCHAR *)f20W},
289 {.vsc = 0x84, .pwsz = (WCHAR *)f21W},
290 {.vsc = 0x85, .pwsz = (WCHAR *)f22W},
291 {.vsc = 0x86, .pwsz = (WCHAR *)f23W},
292 {.vsc = 0x87, .pwsz = (WCHAR *)f24W},
293 {0},
296 static const VSC_LPWSTR key_names_ext[] =
298 {.vsc = 0x1c, .pwsz = (WCHAR *)num_enterW},
299 {.vsc = 0x1d, .pwsz = (WCHAR *)right_ctrlW},
300 {.vsc = 0x35, .pwsz = (WCHAR *)num_divW},
301 {.vsc = 0x37, .pwsz = (WCHAR *)prnt_scrnW},
302 {.vsc = 0x38, .pwsz = (WCHAR *)right_altW},
303 {.vsc = 0x45, .pwsz = (WCHAR *)num_lockW},
304 {.vsc = 0x46, .pwsz = (WCHAR *)breakW},
305 {.vsc = 0x47, .pwsz = (WCHAR *)homeW},
306 {.vsc = 0x48, .pwsz = (WCHAR *)upW},
307 {.vsc = 0x49, .pwsz = (WCHAR *)page_upW},
308 {.vsc = 0x4b, .pwsz = (WCHAR *)leftW},
309 {.vsc = 0x4d, .pwsz = (WCHAR *)rightW},
310 {.vsc = 0x4f, .pwsz = (WCHAR *)endW},
311 {.vsc = 0x50, .pwsz = (WCHAR *)downW},
312 {.vsc = 0x51, .pwsz = (WCHAR *)page_downW},
313 {.vsc = 0x52, .pwsz = (WCHAR *)insertW},
314 {.vsc = 0x53, .pwsz = (WCHAR *)deleteW},
315 {.vsc = 0x54, .pwsz = (WCHAR *)zerozeroW},
316 {.vsc = 0x56, .pwsz = (WCHAR *)helpW},
317 {.vsc = 0x5b, .pwsz = (WCHAR *)left_windowsW},
318 {.vsc = 0x5c, .pwsz = (WCHAR *)right_windowsW},
319 {.vsc = 0x5d, .pwsz = (WCHAR *)applicationW},
320 {0},
323 static const USHORT vsc_to_vk[] =
325 T00, T01, T02, T03, T04, T05, T06, T07,
326 T08, T09, T0A, T0B, T0C, T0D, T0E, T0F,
327 T10, T11, T12, T13, T14, T15, T16, T17,
328 T18, T19, T1A, T1B, T1C, T1D, T1E, T1F,
329 T20, T21, T22, T23, T24, T25, T26, T27,
330 T28, T29, T2A, T2B, T2C, T2D, T2E, T2F,
331 T30, T31, T32, T33, T34, T35, T36 | KBDEXT, T37 | KBDMULTIVK,
332 T38, T39, T3A, T3B, T3C, T3D, T3E, T3F,
333 T40, T41, T42, T43, T44, T45 | KBDEXT | KBDMULTIVK, T46 | KBDMULTIVK, T47 | KBDNUMPAD | KBDSPECIAL,
334 T48 | KBDNUMPAD | KBDSPECIAL, T49 | KBDNUMPAD | KBDSPECIAL, T4A, T4B | KBDNUMPAD | KBDSPECIAL,
335 T4C | KBDNUMPAD | KBDSPECIAL, T4D | KBDNUMPAD | KBDSPECIAL, T4E, T4F | KBDNUMPAD | KBDSPECIAL,
336 T50 | KBDNUMPAD | KBDSPECIAL, T51 | KBDNUMPAD | KBDSPECIAL, T52 | KBDNUMPAD | KBDSPECIAL,
337 T53 | KBDNUMPAD | KBDSPECIAL, T54, T55, T56, T57,
338 T58, T59, T5A, T5B, T5C, T5D, T5E, T5F,
339 T60, T61, T62, T63, T64, T65, T66, T67,
340 T68, T69, T6A, T6B, T6C, T6D, T6E, T6F,
341 T70, T71, T72, T73, T74, T75, T76, T77,
342 T78, T79, T7A, T7B, T7C, T7D, T7E
345 static const VSC_VK vsc_to_vk_e0[] =
347 {0x10, X10 | KBDEXT},
348 {0x19, X19 | KBDEXT},
349 {0x1d, X1D | KBDEXT},
350 {0x20, X20 | KBDEXT},
351 {0x21, X21 | KBDEXT},
352 {0x22, X22 | KBDEXT},
353 {0x24, X24 | KBDEXT},
354 {0x2e, X2E | KBDEXT},
355 {0x30, X30 | KBDEXT},
356 {0x32, X32 | KBDEXT},
357 {0x35, X35 | KBDEXT},
358 {0x37, X37 | KBDEXT},
359 {0x38, X38 | KBDEXT},
360 {0x47, X47 | KBDEXT},
361 {0x48, X48 | KBDEXT},
362 {0x49, X49 | KBDEXT},
363 {0x4b, X4B | KBDEXT},
364 {0x4d, X4D | KBDEXT},
365 {0x4f, X4F | KBDEXT},
366 {0x50, X50 | KBDEXT},
367 {0x51, X51 | KBDEXT},
368 {0x52, X52 | KBDEXT},
369 {0x53, X53 | KBDEXT},
370 {0x5b, X5B | KBDEXT},
371 {0x5c, X5C | KBDEXT},
372 {0x5d, X5D | KBDEXT},
373 {0x5f, X5F | KBDEXT},
374 {0x65, X65 | KBDEXT},
375 {0x66, X66 | KBDEXT},
376 {0x67, X67 | KBDEXT},
377 {0x68, X68 | KBDEXT},
378 {0x69, X69 | KBDEXT},
379 {0x6a, X6A | KBDEXT},
380 {0x6b, X6B | KBDEXT},
381 {0x6c, X6C | KBDEXT},
382 {0x6d, X6D | KBDEXT},
383 {0x1c, X1C | KBDEXT},
384 {0x46, X46 | KBDEXT},
385 {0},
388 static const VSC_VK vsc_to_vk_e1[] =
390 {0x1d, Y1D},
391 {0},
394 static const KBDTABLES kbdus_tables =
396 .pCharModifiers = (MODIFIERS *)&modifiers,
397 .pVkToWcharTable = (VK_TO_WCHAR_TABLE *)vk_to_wchar_table,
398 .pKeyNames = (VSC_LPWSTR *)key_names,
399 .pKeyNamesExt = (VSC_LPWSTR *)key_names_ext,
400 .pusVSCtoVK = (USHORT *)vsc_to_vk,
401 .bMaxVSCtoVK = ARRAY_SIZE(vsc_to_vk),
402 .pVSCtoVK_E0 = (VSC_VK *)vsc_to_vk_e0,
403 .pVSCtoVK_E1 = (VSC_VK *)vsc_to_vk_e1,
404 .fLocaleFlags = MAKELONG(0, KBD_VERSION),
408 LONG global_key_state_counter = 0;
411 static void kbd_tables_init_vsc2vk( const KBDTABLES *tables, BYTE vsc2vk[0x300] )
413 const VSC_VK *entry;
414 WORD vsc;
416 memset( vsc2vk, 0, 0x300 );
418 for (vsc = 0; tables->pusVSCtoVK && vsc <= tables->bMaxVSCtoVK; ++vsc)
420 if (tables->pusVSCtoVK[vsc] == VK__none_) continue;
421 vsc2vk[vsc] = (BYTE)tables->pusVSCtoVK[vsc];
423 for (entry = tables->pVSCtoVK_E0; entry && entry->Vsc; entry++)
425 if (entry->Vk == VK__none_) continue;
426 vsc2vk[entry->Vsc + 0x100] = (BYTE)entry->Vk;
428 for (entry = tables->pVSCtoVK_E1; entry && entry->Vsc; entry++)
430 if (entry->Vk == VK__none_) continue;
431 vsc2vk[entry->Vsc + 0x200] = (BYTE)entry->Vk;
435 #define NEXT_ENTRY(t, e) ((void *)&(e)->wch[(t)->nModifications])
437 static void kbd_tables_init_vk2char( const KBDTABLES *tables, BYTE vk2char[0x100] )
439 const VK_TO_WCHAR_TABLE *table;
440 const VK_TO_WCHARS1 *entry;
442 memset( vk2char, 0, 0x100 );
444 for (table = tables->pVkToWcharTable; table->pVkToWchars; table++)
446 for (entry = table->pVkToWchars; entry->VirtualKey; entry = NEXT_ENTRY(table, entry))
448 if (entry->VirtualKey & ~0xff) continue;
449 vk2char[entry->VirtualKey] = entry->wch[0];
454 static UINT kbd_tables_get_mod_bits( const KBDTABLES *tables, UINT mod )
456 const MODIFIERS *mods = tables->pCharModifiers;
457 WORD bits;
459 for (bits = 0; bits <= mods->wMaxModBits; ++bits)
460 if (mods->ModNumber[bits] == mod) return bits;
462 return -1;
465 static UINT kbd_tables_get_mod_num( const KBDTABLES *tables, const BYTE *state, BOOL caps )
467 const MODIFIERS *mods = tables->pCharModifiers;
468 const VK_TO_BIT *entry;
469 WORD bits = 0;
471 for (entry = mods->pVkToBit; entry->Vk; ++entry)
472 if (state[entry->Vk] & 0x80) bits |= entry->ModBits;
473 if (caps) bits |= KBDSHIFT;
475 if (bits > mods->wMaxModBits) return -1;
476 return mods->ModNumber[bits];
479 static WORD kbd_tables_wchar_to_vkey( const KBDTABLES *tables, WCHAR wch )
481 const VK_TO_WCHAR_TABLE *table;
482 const VK_TO_WCHARS1 *entry;
483 WORD bits;
484 BYTE mod;
486 if (wch == '\x001b') return VK_ESCAPE;
488 for (table = tables->pVkToWcharTable; table->pVkToWchars; table++)
490 for (entry = table->pVkToWchars; entry->VirtualKey; entry = NEXT_ENTRY(table, entry))
492 for (mod = 0; mod < table->nModifications; ++mod)
494 if (entry->wch[mod] == WCH_NONE || entry->wch[mod] != wch) continue;
495 bits = kbd_tables_get_mod_bits( tables, mod );
496 return (bits << 8) | entry->VirtualKey;
501 if (wch >= 0x0001 && wch <= 0x001a) return (0x200) | ('A' + wch - 1); /* CTRL + A-Z */
502 return wch >= 0x0080 ? -1 : 0;
505 static WCHAR kbd_tables_vkey_to_wchar( const KBDTABLES *tables, UINT vkey, const BYTE *state )
507 UINT mod, caps_mod, alt, ctrl, caps;
508 const VK_TO_WCHAR_TABLE *table;
509 const VK_TO_WCHARS1 *entry;
511 alt = state[VK_MENU] & 0x80;
512 ctrl = state[VK_CONTROL] & 0x80;
513 caps = state[VK_CAPITAL] & 1;
515 if (ctrl && alt) return WCH_NONE;
516 if (!ctrl && vkey == VK_ESCAPE) return VK_ESCAPE;
518 mod = caps_mod = kbd_tables_get_mod_num( tables, state, FALSE );
519 if (caps) caps_mod = kbd_tables_get_mod_num( tables, state, TRUE );
521 for (table = tables->pVkToWcharTable; table->pVkToWchars; table++)
523 if (table->nModifications <= mod) continue;
524 for (entry = table->pVkToWchars; entry->VirtualKey; entry = NEXT_ENTRY(table, entry))
526 if (entry->VirtualKey != vkey) continue;
527 if ((entry->Attributes & CAPLOK) && table->nModifications > caps_mod) return entry->wch[caps_mod];
528 return entry->wch[mod];
532 if (ctrl && vkey >= 'A' && vkey <= 'Z') return vkey - 'A' + 1;
533 return WCH_NONE;
536 #undef NEXT_ENTRY
538 /*******************************************************************
539 * NtUserGetForegroundWindow (win32u.@)
541 HWND WINAPI NtUserGetForegroundWindow(void)
543 HWND ret = 0;
545 SERVER_START_REQ( get_thread_input )
547 req->tid = 0;
548 if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->foreground );
550 SERVER_END_REQ;
551 return ret;
554 /* see GetActiveWindow */
555 HWND get_active_window(void)
557 GUITHREADINFO info;
558 info.cbSize = sizeof(info);
559 return NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info ) ? info.hwndActive : 0;
562 /* see GetCapture */
563 HWND get_capture(void)
565 GUITHREADINFO info;
566 info.cbSize = sizeof(info);
567 return NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info ) ? info.hwndCapture : 0;
570 /* see GetFocus */
571 HWND get_focus(void)
573 GUITHREADINFO info;
574 info.cbSize = sizeof(info);
575 return NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info ) ? info.hwndFocus : 0;
578 /**********************************************************************
579 * NtUserAttachThreadInput (win32u.@)
581 BOOL WINAPI NtUserAttachThreadInput( DWORD from, DWORD to, BOOL attach )
583 BOOL ret;
585 SERVER_START_REQ( attach_thread_input )
587 req->tid_from = from;
588 req->tid_to = to;
589 req->attach = attach;
590 ret = !wine_server_call_err( req );
592 SERVER_END_REQ;
593 return ret;
596 /***********************************************************************
597 * __wine_send_input (win32u.@)
599 * Internal SendInput function to allow the graphics driver to inject real events.
601 BOOL CDECL __wine_send_input( HWND hwnd, const INPUT *input, const RAWINPUT *rawinput )
603 return set_ntstatus( send_hardware_message( hwnd, input, rawinput, 0 ));
606 /***********************************************************************
607 * update_mouse_coords
609 * Helper for NtUserSendInput.
611 static void update_mouse_coords( INPUT *input )
613 if (!(input->mi.dwFlags & MOUSEEVENTF_MOVE)) return;
615 if (input->mi.dwFlags & MOUSEEVENTF_ABSOLUTE)
617 RECT rc;
619 if (input->mi.dwFlags & MOUSEEVENTF_VIRTUALDESK)
620 rc = get_virtual_screen_rect( 0 );
621 else
622 rc = get_primary_monitor_rect( 0 );
624 input->mi.dx = rc.left + ((input->mi.dx * (rc.right - rc.left)) >> 16);
625 input->mi.dy = rc.top + ((input->mi.dy * (rc.bottom - rc.top)) >> 16);
627 else
629 int accel[3];
631 /* dx and dy can be negative numbers for relative movements */
632 NtUserSystemParametersInfo( SPI_GETMOUSE, 0, accel, 0 );
634 if (!accel[2]) return;
636 if (abs( input->mi.dx ) > accel[0])
638 input->mi.dx *= 2;
639 if (abs( input->mi.dx ) > accel[1] && accel[2] == 2) input->mi.dx *= 2;
641 if (abs(input->mi.dy) > accel[0])
643 input->mi.dy *= 2;
644 if (abs( input->mi.dy ) > accel[1] && accel[2] == 2) input->mi.dy *= 2;
649 /***********************************************************************
650 * NtUserSendInput (win32u.@)
652 UINT WINAPI NtUserSendInput( UINT count, INPUT *inputs, int size )
654 UINT i;
655 NTSTATUS status = STATUS_SUCCESS;
657 if (size != sizeof(INPUT))
659 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
660 return 0;
663 if (!count)
665 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
666 return 0;
669 if (!inputs)
671 RtlSetLastWin32Error( ERROR_NOACCESS );
672 return 0;
675 for (i = 0; i < count; i++)
677 INPUT input = inputs[i];
678 switch (input.type)
680 case INPUT_MOUSE:
681 /* we need to update the coordinates to what the server expects */
682 update_mouse_coords( &input );
683 /* fallthrough */
684 case INPUT_KEYBOARD:
685 status = send_hardware_message( 0, &input, NULL, SEND_HWMSG_INJECTED );
686 break;
687 case INPUT_HARDWARE:
688 RtlSetLastWin32Error( ERROR_CALL_NOT_IMPLEMENTED );
689 return 0;
692 if (status)
694 RtlSetLastWin32Error( RtlNtStatusToDosError(status) );
695 break;
699 return i;
702 /***********************************************************************
703 * NtUserSetCursorPos (win32u.@)
705 BOOL WINAPI NtUserSetCursorPos( INT x, INT y )
707 POINT pt = { x, y };
708 BOOL ret;
709 INT prev_x, prev_y, new_x, new_y;
710 UINT dpi;
712 if ((dpi = get_thread_dpi()))
714 HMONITOR monitor = monitor_from_point( pt, MONITOR_DEFAULTTOPRIMARY, get_thread_dpi() );
715 pt = map_dpi_point( pt, dpi, get_monitor_dpi( monitor ));
718 SERVER_START_REQ( set_cursor )
720 req->flags = SET_CURSOR_POS;
721 req->x = pt.x;
722 req->y = pt.y;
723 if ((ret = !wine_server_call( req )))
725 prev_x = reply->prev_x;
726 prev_y = reply->prev_y;
727 new_x = reply->new_x;
728 new_y = reply->new_y;
731 SERVER_END_REQ;
732 if (ret && (prev_x != new_x || prev_y != new_y)) user_driver->pSetCursorPos( new_x, new_y );
733 return ret;
736 /***********************************************************************
737 * get_cursor_pos
739 BOOL get_cursor_pos( POINT *pt )
741 BOOL ret;
742 DWORD last_change;
743 UINT dpi;
745 if (!pt) return FALSE;
747 SERVER_START_REQ( set_cursor )
749 if ((ret = !wine_server_call( req )))
751 pt->x = reply->new_x;
752 pt->y = reply->new_y;
753 last_change = reply->last_change;
756 SERVER_END_REQ;
758 /* query new position from graphics driver if we haven't updated recently */
759 if (ret && NtGetTickCount() - last_change > 100) ret = user_driver->pGetCursorPos( pt );
760 if (ret && (dpi = get_thread_dpi()))
762 HMONITOR monitor = monitor_from_point( *pt, MONITOR_DEFAULTTOPRIMARY, 0 );
763 *pt = map_dpi_point( *pt, get_monitor_dpi( monitor ), dpi );
765 return ret;
768 /***********************************************************************
769 * NtUserGetCursorInfo (win32u.@)
771 BOOL WINAPI NtUserGetCursorInfo( CURSORINFO *info )
773 BOOL ret;
775 if (!info) return FALSE;
777 SERVER_START_REQ( get_thread_input )
779 req->tid = 0;
780 if ((ret = !wine_server_call( req )))
782 info->hCursor = wine_server_ptr_handle( reply->cursor );
783 info->flags = reply->show_count >= 0 ? CURSOR_SHOWING : 0;
786 SERVER_END_REQ;
787 get_cursor_pos( &info->ptScreenPos );
788 return ret;
791 static void check_for_events( UINT flags )
793 if (!user_driver->pProcessEvents( flags ))
794 flush_window_surfaces( TRUE );
797 /**********************************************************************
798 * GetAsyncKeyState (win32u.@)
800 SHORT WINAPI NtUserGetAsyncKeyState( INT key )
802 struct user_key_state_info *key_state_info = get_user_thread_info()->key_state;
803 INT counter = global_key_state_counter;
804 BYTE prev_key_state;
805 SHORT ret;
807 if (key < 0 || key >= 256) return 0;
809 check_for_events( QS_INPUT );
811 if (key_state_info && !(key_state_info->state[key] & 0xc0) &&
812 key_state_info->counter == counter && NtGetTickCount() - key_state_info->time < 50)
814 /* use cached value */
815 return 0;
817 else if (!key_state_info)
819 key_state_info = calloc( 1, sizeof(*key_state_info) );
820 get_user_thread_info()->key_state = key_state_info;
823 ret = 0;
824 SERVER_START_REQ( get_key_state )
826 req->async = 1;
827 req->key = key;
828 if (key_state_info)
830 prev_key_state = key_state_info->state[key];
831 wine_server_set_reply( req, key_state_info->state, sizeof(key_state_info->state) );
833 if (!wine_server_call( req ))
835 if (reply->state & 0x40) ret |= 0x0001;
836 if (reply->state & 0x80) ret |= 0x8000;
837 if (key_state_info)
839 /* force refreshing the key state cache - some multithreaded programs
840 * (like Adobe Photoshop CS5) expect that changes to the async key state
841 * are also immediately available in other threads. */
842 if (prev_key_state != key_state_info->state[key])
843 counter = InterlockedIncrement( &global_key_state_counter );
845 key_state_info->time = NtGetTickCount();
846 key_state_info->counter = counter;
850 SERVER_END_REQ;
852 return ret;
855 /***********************************************************************
856 * NtUserGetQueueStatus (win32u.@)
858 DWORD WINAPI NtUserGetQueueStatus( UINT flags )
860 DWORD ret;
862 if (flags & ~(QS_ALLINPUT | QS_ALLPOSTMESSAGE | QS_SMRESULT))
864 RtlSetLastWin32Error( ERROR_INVALID_FLAGS );
865 return 0;
868 check_for_events( flags );
870 SERVER_START_REQ( get_queue_status )
872 req->clear_bits = flags;
873 wine_server_call( req );
874 ret = MAKELONG( reply->changed_bits & flags, reply->wake_bits & flags );
876 SERVER_END_REQ;
877 return ret;
880 /***********************************************************************
881 * get_input_state
883 DWORD get_input_state(void)
885 DWORD ret;
887 check_for_events( QS_INPUT );
889 SERVER_START_REQ( get_queue_status )
891 req->clear_bits = 0;
892 wine_server_call( req );
893 ret = reply->wake_bits & (QS_KEY | QS_MOUSEBUTTON);
895 SERVER_END_REQ;
896 return ret;
899 /***********************************************************************
900 * get_locale_kbd_layout
902 static HKL get_locale_kbd_layout(void)
904 LCID layout;
905 LANGID langid;
907 /* FIXME:
909 * layout = main_key_tab[kbd_layout].lcid;
911 * Winword uses return value of GetKeyboardLayout as a codepage
912 * to translate ANSI keyboard messages to unicode. But we have
913 * a problem with it: for instance Polish keyboard layout is
914 * identical to the US one, and therefore instead of the Polish
915 * locale id we return the US one.
918 NtQueryDefaultLocale( TRUE, &layout );
921 * Microsoft Office expects this value to be something specific
922 * for Japanese and Korean Windows with an IME the value is 0xe001
923 * We should probably check to see if an IME exists and if so then
924 * set this word properly.
926 langid = PRIMARYLANGID( LANGIDFROMLCID( layout ) );
927 if (langid == LANG_CHINESE || langid == LANG_JAPANESE || langid == LANG_KOREAN)
928 layout = MAKELONG( layout, 0xe001 ); /* IME */
929 else
930 layout = MAKELONG( layout, layout );
932 return ULongToHandle( layout );
935 /***********************************************************************
936 * NtUserGetKeyboardLayout (win32u.@)
938 * Device handle for keyboard layout defaulted to
939 * the language id. This is the way Windows default works.
941 HKL WINAPI NtUserGetKeyboardLayout( DWORD thread_id )
943 struct user_thread_info *thread = get_user_thread_info();
944 HKL layout = thread->kbd_layout;
946 if (thread_id && thread_id != GetCurrentThreadId())
947 FIXME( "couldn't return keyboard layout for thread %04x\n", (int)thread_id );
949 if (!layout) return get_locale_kbd_layout();
950 return layout;
953 /**********************************************************************
954 * NtUserGetKeyState (win32u.@)
956 * An application calls the GetKeyState function in response to a
957 * keyboard-input message. This function retrieves the state of the key
958 * at the time the input message was generated.
960 SHORT WINAPI NtUserGetKeyState( INT vkey )
962 SHORT retval = 0;
964 SERVER_START_REQ( get_key_state )
966 req->key = vkey;
967 if (!wine_server_call( req )) retval = (signed char)(reply->state & 0x81);
969 SERVER_END_REQ;
970 TRACE("key (0x%x) -> %x\n", vkey, retval);
971 return retval;
974 /**********************************************************************
975 * NtUserGetKeyboardState (win32u.@)
977 BOOL WINAPI NtUserGetKeyboardState( BYTE *state )
979 BOOL ret;
980 UINT i;
982 TRACE("(%p)\n", state);
984 memset( state, 0, 256 );
985 SERVER_START_REQ( get_key_state )
987 req->key = -1;
988 wine_server_set_reply( req, state, 256 );
989 ret = !wine_server_call_err( req );
990 for (i = 0; i < 256; i++) state[i] &= 0x81;
992 SERVER_END_REQ;
993 return ret;
996 /**********************************************************************
997 * NtUserSetKeyboardState (win32u.@)
999 BOOL WINAPI NtUserSetKeyboardState( BYTE *state )
1001 BOOL ret;
1003 SERVER_START_REQ( set_key_state )
1005 wine_server_add_data( req, state, 256 );
1006 ret = !wine_server_call_err( req );
1008 SERVER_END_REQ;
1009 return ret;
1012 /******************************************************************************
1013 * NtUserVkKeyScanEx (win32u.@)
1015 WORD WINAPI NtUserVkKeyScanEx( WCHAR chr, HKL layout )
1017 const KBDTABLES *kbd_tables = &kbdus_tables;
1018 SHORT ret;
1020 TRACE_(keyboard)( "chr %s, layout %p\n", debugstr_wn(&chr, 1), layout );
1022 if ((ret = user_driver->pVkKeyScanEx( chr, layout )) != -256) return ret;
1023 ret = kbd_tables_wchar_to_vkey( kbd_tables, chr );
1025 TRACE_(keyboard)( "ret %04x\n", ret );
1026 return ret;
1030 /******************************************************************************
1031 * NtUserMapVirtualKeyEx (win32u.@)
1033 UINT WINAPI NtUserMapVirtualKeyEx( UINT code, UINT type, HKL layout )
1035 const KBDTABLES *kbd_tables = &kbdus_tables;
1036 BYTE vsc2vk[0x300], vk2char[0x100];
1037 UINT ret;
1039 TRACE_(keyboard)( "code %u, type %u, layout %p.\n", code, type, layout );
1041 if ((ret = user_driver->pMapVirtualKeyEx( code, type, layout )) != -1) return ret;
1043 kbd_tables_init_vsc2vk( kbd_tables, vsc2vk );
1044 kbd_tables_init_vk2char( kbd_tables, vk2char );
1046 switch (type)
1048 case MAPVK_VK_TO_VSC_EX:
1049 case MAPVK_VK_TO_VSC:
1050 switch (code)
1052 case VK_SHIFT: code = VK_LSHIFT; break;
1053 case VK_CONTROL: code = VK_LCONTROL; break;
1054 case VK_MENU: code = VK_LMENU; break;
1055 case VK_NUMPAD0: code = VK_INSERT; break;
1056 case VK_NUMPAD1: code = VK_END; break;
1057 case VK_NUMPAD2: code = VK_DOWN; break;
1058 case VK_NUMPAD3: code = VK_NEXT; break;
1059 case VK_NUMPAD4: code = VK_LEFT; break;
1060 case VK_NUMPAD5: code = VK_CLEAR; break;
1061 case VK_NUMPAD6: code = VK_RIGHT; break;
1062 case VK_NUMPAD7: code = VK_HOME; break;
1063 case VK_NUMPAD8: code = VK_UP; break;
1064 case VK_NUMPAD9: code = VK_PRIOR; break;
1065 case VK_DECIMAL: code = VK_DELETE; break;
1068 for (ret = 0; ret < ARRAY_SIZE(vsc2vk); ++ret) if (vsc2vk[ret] == code) break;
1069 if (ret >= ARRAY_SIZE(vsc2vk)) ret = 0;
1071 if (type == MAPVK_VK_TO_VSC)
1073 if (ret >= 0x200) ret = 0;
1074 else ret &= 0xff;
1076 else if (ret >= 0x100) ret += 0xdf00;
1077 break;
1078 case MAPVK_VSC_TO_VK:
1079 case MAPVK_VSC_TO_VK_EX:
1080 if (code & 0xe000) code -= 0xdf00;
1081 if (code >= ARRAY_SIZE(vsc2vk)) ret = 0;
1082 else ret = vsc2vk[code];
1084 if (type == MAPVK_VSC_TO_VK)
1086 switch (ret)
1088 case VK_LSHIFT: case VK_RSHIFT: ret = VK_SHIFT; break;
1089 case VK_LCONTROL: case VK_RCONTROL: ret = VK_CONTROL; break;
1090 case VK_LMENU: case VK_RMENU: ret = VK_MENU; break;
1093 break;
1094 case MAPVK_VK_TO_CHAR:
1095 if (code >= ARRAY_SIZE(vk2char)) ret = 0;
1096 else if (code >= 'A' && code <= 'Z') ret = code;
1097 else ret = vk2char[code];
1098 break;
1099 default:
1100 FIXME_(keyboard)( "unknown type %d\n", type );
1101 return 0;
1104 TRACE_(keyboard)( "returning 0x%04x\n", ret );
1105 return ret;
1108 /****************************************************************************
1109 * NtUserGetKeyNameText (win32u.@)
1111 INT WINAPI NtUserGetKeyNameText( LONG lparam, WCHAR *buffer, INT size )
1113 INT code = ((lparam >> 16) & 0x1ff), vkey, len;
1114 const KBDTABLES *kbd_tables = &kbdus_tables;
1115 VSC_LPWSTR *key_name;
1116 BYTE vsc2vk[0x300];
1118 TRACE_(keyboard)( "lparam %#x, buffer %p, size %d.\n", (int)lparam, buffer, size );
1120 if (!buffer || !size) return 0;
1121 if ((len = user_driver->pGetKeyNameText( lparam, buffer, size )) >= 0) return len;
1123 kbd_tables_init_vsc2vk( kbd_tables, vsc2vk );
1125 if (lparam & 0x2000000)
1127 switch ((vkey = vsc2vk[code]))
1129 case VK_RSHIFT:
1130 case VK_RCONTROL:
1131 case VK_RMENU:
1132 for (code = 0; code < ARRAY_SIZE(vsc2vk); ++code)
1133 if (vsc2vk[code] == (vkey - 1)) break;
1134 break;
1138 if (code < 0x100) key_name = kbd_tables->pKeyNames;
1139 else key_name = kbd_tables->pKeyNamesExt;
1140 while (key_name->vsc && key_name->vsc != (BYTE)code) key_name++;
1142 if (key_name->vsc == (BYTE)code)
1144 len = min( size - 1, wcslen( key_name->pwsz ) );
1145 memcpy( buffer, key_name->pwsz, len * sizeof(WCHAR) );
1147 else if (size > 1)
1149 HKL hkl = NtUserGetKeyboardLayout( 0 );
1150 vkey = NtUserMapVirtualKeyEx( code & 0xff, MAPVK_VSC_TO_VK, hkl );
1151 buffer[0] = NtUserMapVirtualKeyEx( vkey, MAPVK_VK_TO_CHAR, hkl );
1152 len = 1;
1154 buffer[len] = 0;
1156 TRACE_(keyboard)( "ret %d, str %s.\n", len, debugstr_w(buffer) );
1157 return len;
1160 /****************************************************************************
1161 * NtUserToUnicodeEx (win32u.@)
1163 INT WINAPI NtUserToUnicodeEx( UINT virt, UINT scan, const BYTE *state,
1164 WCHAR *str, int size, UINT flags, HKL layout )
1166 const KBDTABLES *kbd_tables = &kbdus_tables;
1167 WCHAR buffer[2] = {0};
1168 INT len;
1170 TRACE_(keyboard)( "virt %#x, scan %#x, state %p, str %p, size %d, flags %#x, layout %p.\n",
1171 virt, scan, state, str, size, flags, layout );
1173 if (!state) return 0;
1174 if ((len = user_driver->pToUnicodeEx( virt, scan, state, str, size, flags, layout )) >= -1)
1175 return len;
1177 if (scan & 0x8000) buffer[0] = 0; /* key up */
1178 else buffer[0] = kbd_tables_vkey_to_wchar( kbd_tables, virt, state );
1180 if (buffer[0] != WCH_NONE) len = 1;
1181 else buffer[0] = len = 0;
1183 lstrcpynW( str, buffer, size );
1185 TRACE_(keyboard)( "ret %d, str %s.\n", len, debugstr_w(str) );
1186 return len;
1189 /**********************************************************************
1190 * NtUserActivateKeyboardLayout (win32u.@)
1192 HKL WINAPI NtUserActivateKeyboardLayout( HKL layout, UINT flags )
1194 struct user_thread_info *info = get_user_thread_info();
1195 HKL old_layout;
1196 LCID locale;
1197 HWND focus;
1199 TRACE_(keyboard)( "layout %p, flags %x\n", layout, flags );
1201 if (flags) FIXME_(keyboard)( "flags %x not supported\n", flags );
1203 if (layout == (HKL)HKL_NEXT || layout == (HKL)HKL_PREV)
1205 RtlSetLastWin32Error( ERROR_CALL_NOT_IMPLEMENTED );
1206 FIXME_(keyboard)( "HKL_NEXT and HKL_PREV not supported\n" );
1207 return 0;
1210 if (LOWORD(layout) != MAKELANGID(LANG_INVARIANT, SUBLANG_DEFAULT) &&
1211 (NtQueryDefaultLocale( TRUE, &locale ) || LOWORD(layout) != locale))
1213 RtlSetLastWin32Error( ERROR_CALL_NOT_IMPLEMENTED );
1214 FIXME_(keyboard)( "Changing user locale is not supported\n" );
1215 return 0;
1218 if (!user_driver->pActivateKeyboardLayout( layout, flags ))
1219 return 0;
1221 old_layout = info->kbd_layout;
1222 if (old_layout != layout)
1224 HWND ime_hwnd = get_default_ime_window( 0 );
1225 const NLS_LOCALE_DATA *data;
1226 CHARSETINFO cs = {0};
1228 if (ime_hwnd) send_message( ime_hwnd, WM_IME_INTERNAL, IME_INTERNAL_HKL_DEACTIVATE, HandleToUlong(old_layout) );
1230 if (HIWORD(layout) & 0x8000)
1231 FIXME( "Aliased keyboard layout not yet implemented\n" );
1232 else if (!(data = get_locale_data( HIWORD(layout) )))
1233 WARN( "Failed to find locale data for %04x\n", HIWORD(layout) );
1234 else
1235 translate_charset_info( ULongToPtr(data->idefaultansicodepage), &cs, TCI_SRCCODEPAGE );
1237 info->kbd_layout = layout;
1238 info->kbd_layout_id = 0;
1240 if (ime_hwnd) send_message( ime_hwnd, WM_IME_INTERNAL, IME_INTERNAL_HKL_ACTIVATE, HandleToUlong(layout) );
1242 if ((focus = get_focus()) && get_window_thread( focus, NULL ) == GetCurrentThreadId())
1243 send_message( focus, WM_INPUTLANGCHANGE, cs.ciCharset, (LPARAM)layout );
1246 if (!old_layout) return get_locale_kbd_layout();
1247 return old_layout;
1252 /***********************************************************************
1253 * NtUserGetKeyboardLayoutList (win32u.@)
1255 * Return number of values available if either input parm is
1256 * 0, per MS documentation.
1258 UINT WINAPI NtUserGetKeyboardLayoutList( INT size, HKL *layouts )
1260 char buffer[4096];
1261 KEY_NODE_INFORMATION *key_info = (KEY_NODE_INFORMATION *)buffer;
1262 KEY_VALUE_PARTIAL_INFORMATION *value_info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1263 DWORD count, tmp, i = 0;
1264 HKEY hkey, subkey;
1265 HKL layout;
1267 TRACE_(keyboard)( "size %d, layouts %p.\n", size, layouts );
1269 if ((count = user_driver->pGetKeyboardLayoutList( size, layouts )) != ~0) return count;
1271 layout = get_locale_kbd_layout();
1272 count = 0;
1274 count++;
1275 if (size && layouts)
1277 layouts[count - 1] = layout;
1278 if (count == size) return count;
1281 if ((hkey = reg_open_key( NULL, keyboard_layouts_keyW, sizeof(keyboard_layouts_keyW) )))
1283 while (!NtEnumerateKey( hkey, i++, KeyNodeInformation, key_info,
1284 sizeof(buffer) - sizeof(WCHAR), &tmp ))
1286 if (!(subkey = reg_open_key( hkey, key_info->Name, key_info->NameLength ))) continue;
1287 key_info->Name[key_info->NameLength / sizeof(WCHAR)] = 0;
1288 tmp = wcstoul( key_info->Name, NULL, 16 );
1289 if (query_reg_ascii_value( subkey, "Layout Id", value_info, sizeof(buffer) ) &&
1290 value_info->Type == REG_SZ)
1291 tmp = 0xf000 | (wcstoul( (const WCHAR *)value_info->Data, NULL, 16 ) & 0xfff);
1292 NtClose( subkey );
1294 tmp = MAKELONG( LOWORD( layout ), LOWORD( tmp ) );
1295 if (layout == UlongToHandle( tmp )) continue;
1297 count++;
1298 if (size && layouts)
1300 layouts[count - 1] = UlongToHandle( tmp );
1301 if (count == size) break;
1304 NtClose( hkey );
1307 return count;
1310 /****************************************************************************
1311 * NtUserGetKeyboardLayoutName (win32u.@)
1313 BOOL WINAPI NtUserGetKeyboardLayoutName( WCHAR *name )
1315 struct user_thread_info *info = get_user_thread_info();
1316 char buffer[4096];
1317 KEY_NODE_INFORMATION *key = (KEY_NODE_INFORMATION *)buffer;
1318 KEY_VALUE_PARTIAL_INFORMATION *value = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1319 WCHAR klid[KL_NAMELENGTH];
1320 UINT id;
1321 ULONG len, i = 0;
1322 HKEY hkey, subkey;
1323 HKL layout;
1325 TRACE_(keyboard)( "name %p\n", name );
1327 if (!name)
1329 RtlSetLastWin32Error( ERROR_NOACCESS );
1330 return FALSE;
1333 if (info->kbd_layout_id)
1335 sprintf( buffer, "%08X", info->kbd_layout_id );
1336 asciiz_to_unicode( name, buffer );
1337 return TRUE;
1340 layout = NtUserGetKeyboardLayout( 0 );
1341 id = HandleToUlong( layout );
1342 if (HIWORD( id ) == LOWORD( id )) id = LOWORD( id );
1343 sprintf( buffer, "%08X", id );
1344 asciiz_to_unicode( name, buffer );
1346 if ((hkey = reg_open_key( NULL, keyboard_layouts_keyW, sizeof(keyboard_layouts_keyW) )))
1348 while (!NtEnumerateKey( hkey, i++, KeyNodeInformation, key,
1349 sizeof(buffer) - sizeof(WCHAR), &len ))
1351 if (!(subkey = reg_open_key( hkey, key->Name, key->NameLength ))) continue;
1352 memcpy( klid, key->Name, key->NameLength );
1353 klid[key->NameLength / sizeof(WCHAR)] = 0;
1354 if (query_reg_ascii_value( subkey, "Layout Id", value, sizeof(buffer) ) &&
1355 value->Type == REG_SZ)
1356 id = 0xf000 | (wcstoul( (const WCHAR *)value->Data, NULL, 16 ) & 0xfff);
1357 else
1358 id = wcstoul( klid, NULL, 16 );
1359 NtClose( subkey );
1361 if (HIWORD( layout ) == id)
1363 lstrcpynW( name, klid, KL_NAMELENGTH );
1364 break;
1367 NtClose( hkey );
1370 info->kbd_layout_id = wcstoul( name, NULL, 16 );
1372 TRACE_(keyboard)( "ret %s\n", debugstr_w( name ) );
1373 return TRUE;
1376 /***********************************************************************
1377 * NtUserRegisterHotKey (win32u.@)
1379 BOOL WINAPI NtUserRegisterHotKey( HWND hwnd, INT id, UINT modifiers, UINT vk )
1381 BOOL ret;
1382 int replaced = 0;
1384 TRACE_(keyboard)( "(%p,%d,0x%08x,%X)\n", hwnd, id, modifiers, vk );
1386 if ((!hwnd || is_current_thread_window( hwnd )) &&
1387 !user_driver->pRegisterHotKey( hwnd, modifiers, vk ))
1388 return FALSE;
1390 SERVER_START_REQ( register_hotkey )
1392 req->window = wine_server_user_handle( hwnd );
1393 req->id = id;
1394 req->flags = modifiers;
1395 req->vkey = vk;
1396 if ((ret = !wine_server_call_err( req )))
1398 replaced = reply->replaced;
1399 modifiers = reply->flags;
1400 vk = reply->vkey;
1403 SERVER_END_REQ;
1405 if (ret && replaced)
1406 user_driver->pUnregisterHotKey(hwnd, modifiers, vk);
1408 return ret;
1411 /***********************************************************************
1412 * NtUserUnregisterHotKey (win32u.@)
1414 BOOL WINAPI NtUserUnregisterHotKey( HWND hwnd, INT id )
1416 BOOL ret;
1417 UINT modifiers, vk;
1419 TRACE_(keyboard)("(%p,%d)\n",hwnd,id);
1421 SERVER_START_REQ( unregister_hotkey )
1423 req->window = wine_server_user_handle( hwnd );
1424 req->id = id;
1425 if ((ret = !wine_server_call_err( req )))
1427 modifiers = reply->flags;
1428 vk = reply->vkey;
1431 SERVER_END_REQ;
1433 if (ret)
1434 user_driver->pUnregisterHotKey(hwnd, modifiers, vk);
1436 return ret;
1439 /***********************************************************************
1440 * NtUserGetMouseMovePointsEx (win32u.@)
1442 int WINAPI NtUserGetMouseMovePointsEx( UINT size, MOUSEMOVEPOINT *ptin, MOUSEMOVEPOINT *ptout,
1443 int count, DWORD resolution )
1445 cursor_pos_t *pos, positions[64];
1446 int copied;
1447 unsigned int i;
1450 TRACE( "%d, %p, %p, %d, %d\n", size, ptin, ptout, count, (int)resolution );
1452 if ((size != sizeof(MOUSEMOVEPOINT)) || (count < 0) || (count > ARRAY_SIZE( positions )))
1454 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
1455 return -1;
1458 if (!ptin || (!ptout && count))
1460 RtlSetLastWin32Error( ERROR_NOACCESS );
1461 return -1;
1464 if (resolution != GMMP_USE_DISPLAY_POINTS)
1466 FIXME( "only GMMP_USE_DISPLAY_POINTS is supported for now\n" );
1467 RtlSetLastWin32Error( ERROR_POINT_NOT_FOUND );
1468 return -1;
1471 SERVER_START_REQ( get_cursor_history )
1473 wine_server_set_reply( req, &positions, sizeof(positions) );
1474 if (wine_server_call_err( req )) return -1;
1476 SERVER_END_REQ;
1478 for (i = 0; i < ARRAY_SIZE( positions ); i++)
1480 pos = &positions[i];
1481 if (ptin->x == pos->x && ptin->y == pos->y && (!ptin->time || ptin->time == pos->time))
1482 break;
1485 if (i == ARRAY_SIZE( positions ))
1487 RtlSetLastWin32Error( ERROR_POINT_NOT_FOUND );
1488 return -1;
1491 for (copied = 0; copied < count && i < ARRAY_SIZE( positions ); copied++, i++)
1493 pos = &positions[i];
1494 ptout[copied].x = pos->x;
1495 ptout[copied].y = pos->y;
1496 ptout[copied].time = pos->time;
1497 ptout[copied].dwExtraInfo = pos->info;
1500 return copied;
1503 static WORD get_key_state(void)
1505 WORD ret = 0;
1507 if (get_system_metrics( SM_SWAPBUTTON ))
1509 if (NtUserGetAsyncKeyState(VK_RBUTTON) & 0x80) ret |= MK_LBUTTON;
1510 if (NtUserGetAsyncKeyState(VK_LBUTTON) & 0x80) ret |= MK_RBUTTON;
1512 else
1514 if (NtUserGetAsyncKeyState(VK_LBUTTON) & 0x80) ret |= MK_LBUTTON;
1515 if (NtUserGetAsyncKeyState(VK_RBUTTON) & 0x80) ret |= MK_RBUTTON;
1517 if (NtUserGetAsyncKeyState(VK_MBUTTON) & 0x80) ret |= MK_MBUTTON;
1518 if (NtUserGetAsyncKeyState(VK_SHIFT) & 0x80) ret |= MK_SHIFT;
1519 if (NtUserGetAsyncKeyState(VK_CONTROL) & 0x80) ret |= MK_CONTROL;
1520 if (NtUserGetAsyncKeyState(VK_XBUTTON1) & 0x80) ret |= MK_XBUTTON1;
1521 if (NtUserGetAsyncKeyState(VK_XBUTTON2) & 0x80) ret |= MK_XBUTTON2;
1522 return ret;
1525 struct tracking_list
1527 TRACKMOUSEEVENT info;
1528 POINT pos; /* center of hover rectangle */
1531 /* FIXME: move tracking stuff into per-thread data */
1532 static struct tracking_list tracking_info;
1534 static void check_mouse_leave( HWND hwnd, int hittest )
1536 if (tracking_info.info.hwndTrack != hwnd)
1538 if (tracking_info.info.dwFlags & TME_NONCLIENT)
1539 NtUserPostMessage( tracking_info.info.hwndTrack, WM_NCMOUSELEAVE, 0, 0 );
1540 else
1541 NtUserPostMessage( tracking_info.info.hwndTrack, WM_MOUSELEAVE, 0, 0 );
1543 tracking_info.info.dwFlags &= ~TME_LEAVE;
1545 else
1547 if (hittest == HTCLIENT)
1549 if (tracking_info.info.dwFlags & TME_NONCLIENT)
1551 NtUserPostMessage( tracking_info.info.hwndTrack, WM_NCMOUSELEAVE, 0, 0 );
1552 tracking_info.info.dwFlags &= ~TME_LEAVE;
1555 else
1557 if (!(tracking_info.info.dwFlags & TME_NONCLIENT))
1559 NtUserPostMessage( tracking_info.info.hwndTrack, WM_MOUSELEAVE, 0, 0 );
1560 tracking_info.info.dwFlags &= ~TME_LEAVE;
1566 void update_mouse_tracking_info( HWND hwnd )
1568 int hover_width = 0, hover_height = 0, hittest;
1569 POINT pos;
1571 TRACE( "hwnd %p\n", hwnd );
1573 get_cursor_pos( &pos );
1574 hwnd = window_from_point( hwnd, pos, &hittest );
1576 TRACE( "point %s hwnd %p hittest %d\n", wine_dbgstr_point(&pos), hwnd, hittest );
1578 NtUserSystemParametersInfo( SPI_GETMOUSEHOVERWIDTH, 0, &hover_width, 0 );
1579 NtUserSystemParametersInfo( SPI_GETMOUSEHOVERHEIGHT, 0, &hover_height, 0 );
1581 TRACE( "tracked pos %s, current pos %s, hover width %d, hover height %d\n",
1582 wine_dbgstr_point(&tracking_info.pos), wine_dbgstr_point(&pos),
1583 hover_width, hover_height );
1585 if (tracking_info.info.dwFlags & TME_LEAVE)
1586 check_mouse_leave( hwnd, hittest );
1588 if (tracking_info.info.hwndTrack != hwnd)
1589 tracking_info.info.dwFlags &= ~TME_HOVER;
1591 if (tracking_info.info.dwFlags & TME_HOVER)
1593 /* has the cursor moved outside the rectangle centered around pos? */
1594 if ((abs( pos.x - tracking_info.pos.x ) > (hover_width / 2)) ||
1595 (abs( pos.y - tracking_info.pos.y ) > (hover_height / 2)))
1597 tracking_info.pos = pos;
1599 else
1601 if (hittest == HTCLIENT)
1603 screen_to_client(hwnd, &pos);
1604 TRACE( "client cursor pos %s\n", wine_dbgstr_point(&pos) );
1606 NtUserPostMessage( tracking_info.info.hwndTrack, WM_MOUSEHOVER,
1607 get_key_state(), MAKELPARAM( pos.x, pos.y ) );
1609 else
1611 if (tracking_info.info.dwFlags & TME_NONCLIENT)
1612 NtUserPostMessage( tracking_info.info.hwndTrack, WM_NCMOUSEHOVER,
1613 hittest, MAKELPARAM( pos.x, pos.y ) );
1616 /* stop tracking mouse hover */
1617 tracking_info.info.dwFlags &= ~TME_HOVER;
1621 /* stop the timer if the tracking list is empty */
1622 if (!(tracking_info.info.dwFlags & (TME_HOVER | TME_LEAVE)))
1624 kill_system_timer( tracking_info.info.hwndTrack, SYSTEM_TIMER_TRACK_MOUSE );
1625 tracking_info.info.hwndTrack = 0;
1626 tracking_info.info.dwFlags = 0;
1627 tracking_info.info.dwHoverTime = 0;
1631 /***********************************************************************
1632 * NtUserTrackMouseEvent (win32u.@)
1634 BOOL WINAPI NtUserTrackMouseEvent( TRACKMOUSEEVENT *info )
1636 DWORD hover_time;
1637 int hittest;
1638 HWND hwnd;
1639 POINT pos;
1641 TRACE( "size %u, flags %#x, hwnd %p, time %u\n",
1642 (int)info->cbSize, (int)info->dwFlags, info->hwndTrack, (int)info->dwHoverTime );
1644 if (info->cbSize != sizeof(TRACKMOUSEEVENT))
1646 WARN( "wrong size %u\n", (int)info->cbSize );
1647 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
1648 return FALSE;
1651 if (info->dwFlags & TME_QUERY)
1653 *info = tracking_info.info;
1654 info->cbSize = sizeof(TRACKMOUSEEVENT);
1655 return TRUE;
1658 if (!is_window( info->hwndTrack ))
1660 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE );
1661 return FALSE;
1664 hover_time = (info->dwFlags & TME_HOVER) ? info->dwHoverTime : HOVER_DEFAULT;
1666 if (hover_time == HOVER_DEFAULT || hover_time == 0)
1667 NtUserSystemParametersInfo( SPI_GETMOUSEHOVERTIME, 0, &hover_time, 0 );
1669 get_cursor_pos( &pos );
1670 hwnd = window_from_point( info->hwndTrack, pos, &hittest );
1671 TRACE( "point %s hwnd %p hittest %d\n", wine_dbgstr_point(&pos), hwnd, hittest );
1673 if (info->dwFlags & ~(TME_CANCEL | TME_HOVER | TME_LEAVE | TME_NONCLIENT))
1674 FIXME( "ignoring flags %#x\n", (int)info->dwFlags & ~(TME_CANCEL | TME_HOVER | TME_LEAVE | TME_NONCLIENT) );
1676 if (info->dwFlags & TME_CANCEL)
1678 if (tracking_info.info.hwndTrack == info->hwndTrack)
1680 tracking_info.info.dwFlags &= ~(info->dwFlags & ~TME_CANCEL);
1682 /* if we aren't tracking on hover or leave remove this entry */
1683 if (!(tracking_info.info.dwFlags & (TME_HOVER | TME_LEAVE)))
1685 kill_system_timer( tracking_info.info.hwndTrack, SYSTEM_TIMER_TRACK_MOUSE );
1686 tracking_info.info.hwndTrack = 0;
1687 tracking_info.info.dwFlags = 0;
1688 tracking_info.info.dwHoverTime = 0;
1692 else
1694 /* In our implementation, it's possible that another window will receive
1695 * WM_MOUSEMOVE and call TrackMouseEvent before TrackMouseEventProc is
1696 * called. In such a situation, post the WM_MOUSELEAVE now. */
1697 if ((tracking_info.info.dwFlags & TME_LEAVE) && tracking_info.info.hwndTrack != NULL)
1698 check_mouse_leave(hwnd, hittest);
1700 kill_system_timer( tracking_info.info.hwndTrack, SYSTEM_TIMER_TRACK_MOUSE );
1701 tracking_info.info.hwndTrack = 0;
1702 tracking_info.info.dwFlags = 0;
1703 tracking_info.info.dwHoverTime = 0;
1705 if (info->hwndTrack == hwnd)
1707 /* Adding new mouse event to the tracking list */
1708 tracking_info.info = *info;
1709 tracking_info.info.dwHoverTime = hover_time;
1711 /* Initialize HoverInfo variables even if not hover tracking */
1712 tracking_info.pos = pos;
1714 NtUserSetSystemTimer( tracking_info.info.hwndTrack, SYSTEM_TIMER_TRACK_MOUSE, hover_time );
1718 return TRUE;
1721 /**********************************************************************
1722 * set_capture_window
1724 BOOL set_capture_window( HWND hwnd, UINT gui_flags, HWND *prev_ret )
1726 HWND previous = 0;
1727 UINT flags = 0;
1728 BOOL ret;
1730 if (gui_flags & GUI_INMENUMODE) flags |= CAPTURE_MENU;
1731 if (gui_flags & GUI_INMOVESIZE) flags |= CAPTURE_MOVESIZE;
1733 SERVER_START_REQ( set_capture_window )
1735 req->handle = wine_server_user_handle( hwnd );
1736 req->flags = flags;
1737 if ((ret = !wine_server_call_err( req )))
1739 previous = wine_server_ptr_handle( reply->previous );
1740 hwnd = wine_server_ptr_handle( reply->full_handle );
1743 SERVER_END_REQ;
1745 if (ret)
1747 user_driver->pSetCapture( hwnd, gui_flags );
1749 if (previous)
1750 send_message( previous, WM_CAPTURECHANGED, 0, (LPARAM)hwnd );
1752 if (prev_ret) *prev_ret = previous;
1754 return ret;
1757 /**********************************************************************
1758 * NtUserSetCapture (win32u.@)
1760 HWND WINAPI NtUserSetCapture( HWND hwnd )
1762 HWND previous = 0;
1764 set_capture_window( hwnd, 0, &previous );
1765 return previous;
1768 /**********************************************************************
1769 * release_capture
1771 BOOL WINAPI release_capture(void)
1773 BOOL ret = set_capture_window( 0, 0, NULL );
1775 /* Somebody may have missed some mouse movements */
1776 if (ret)
1778 INPUT input = { .type = INPUT_MOUSE };
1779 input.mi.dwFlags = MOUSEEVENTF_MOVE;
1780 NtUserSendInput( 1, &input, sizeof(input) );
1783 return ret;
1786 /*****************************************************************
1787 * set_focus_window
1789 * Change the focus window, sending the WM_SETFOCUS and WM_KILLFOCUS messages
1791 static HWND set_focus_window( HWND hwnd )
1793 HWND previous = 0, ime_hwnd;
1794 BOOL ret;
1796 SERVER_START_REQ( set_focus_window )
1798 req->handle = wine_server_user_handle( hwnd );
1799 if ((ret = !wine_server_call_err( req )))
1800 previous = wine_server_ptr_handle( reply->previous );
1802 SERVER_END_REQ;
1803 if (!ret) return 0;
1804 if (previous == hwnd) return previous;
1806 if (previous)
1808 send_message( previous, WM_KILLFOCUS, (WPARAM)hwnd, 0 );
1810 ime_hwnd = get_default_ime_window( previous );
1811 if (ime_hwnd)
1812 send_message( ime_hwnd, WM_IME_INTERNAL, IME_INTERNAL_DEACTIVATE,
1813 HandleToUlong(previous) );
1815 if (hwnd != get_focus()) return previous; /* changed by the message */
1817 if (is_window(hwnd))
1819 user_driver->pSetFocus(hwnd);
1821 ime_hwnd = get_default_ime_window( hwnd );
1822 if (ime_hwnd)
1823 send_message( ime_hwnd, WM_IME_INTERNAL, IME_INTERNAL_ACTIVATE,
1824 HandleToUlong(hwnd) );
1826 if (previous)
1827 NtUserNotifyWinEvent( EVENT_OBJECT_FOCUS, hwnd, OBJID_CLIENT, 0 );
1829 send_message( hwnd, WM_SETFOCUS, (WPARAM)previous, 0 );
1831 return previous;
1834 /*******************************************************************
1835 * set_active_window
1837 static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus )
1839 HWND previous = get_active_window();
1840 BOOL ret;
1841 DWORD old_thread, new_thread;
1842 CBTACTIVATESTRUCT cbt;
1844 if (previous == hwnd)
1846 if (prev) *prev = hwnd;
1847 return TRUE;
1850 /* call CBT hook chain */
1851 cbt.fMouse = mouse;
1852 cbt.hWndActive = previous;
1853 if (call_hooks( WH_CBT, HCBT_ACTIVATE, (WPARAM)hwnd, (LPARAM)&cbt, sizeof(cbt) )) return FALSE;
1855 if (is_window( previous ))
1857 send_message( previous, WM_NCACTIVATE, FALSE, (LPARAM)hwnd );
1858 send_message( previous, WM_ACTIVATE,
1859 MAKEWPARAM( WA_INACTIVE, is_iconic(previous) ), (LPARAM)hwnd );
1862 SERVER_START_REQ( set_active_window )
1864 req->handle = wine_server_user_handle( hwnd );
1865 if ((ret = !wine_server_call_err( req )))
1866 previous = wine_server_ptr_handle( reply->previous );
1868 SERVER_END_REQ;
1869 if (!ret) return FALSE;
1870 if (prev) *prev = previous;
1871 if (previous == hwnd) return TRUE;
1873 if (hwnd)
1875 /* send palette messages */
1876 if (send_message( hwnd, WM_QUERYNEWPALETTE, 0, 0 ))
1877 send_message_timeout( HWND_BROADCAST, WM_PALETTEISCHANGING, (WPARAM)hwnd, 0,
1878 SMTO_ABORTIFHUNG, 2000, FALSE );
1879 if (!is_window(hwnd)) return FALSE;
1882 old_thread = previous ? get_window_thread( previous, NULL ) : 0;
1883 new_thread = hwnd ? get_window_thread( hwnd, NULL ) : 0;
1885 if (old_thread != new_thread)
1887 HWND *list, *phwnd;
1889 if ((list = list_window_children( NULL, get_desktop_window(), NULL, 0 )))
1891 if (old_thread)
1893 for (phwnd = list; *phwnd; phwnd++)
1895 if (get_window_thread( *phwnd, NULL ) == old_thread)
1896 send_message( *phwnd, WM_ACTIVATEAPP, 0, new_thread );
1899 if (new_thread)
1901 for (phwnd = list; *phwnd; phwnd++)
1903 if (get_window_thread( *phwnd, NULL ) == new_thread)
1904 send_message( *phwnd, WM_ACTIVATEAPP, 1, old_thread );
1907 free( list );
1911 if (is_window(hwnd))
1913 send_message( hwnd, WM_NCACTIVATE, hwnd == NtUserGetForegroundWindow(), (LPARAM)previous );
1914 send_message( hwnd, WM_ACTIVATE,
1915 MAKEWPARAM( mouse ? WA_CLICKACTIVE : WA_ACTIVE, is_iconic(hwnd) ),
1916 (LPARAM)previous );
1917 if (NtUserGetAncestor( hwnd, GA_PARENT ) == get_desktop_window())
1918 NtUserPostMessage( get_desktop_window(), WM_PARENTNOTIFY, WM_NCACTIVATE, (LPARAM)hwnd );
1921 /* now change focus if necessary */
1922 if (focus)
1924 GUITHREADINFO info;
1926 info.cbSize = sizeof(info);
1927 NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info );
1928 /* Do not change focus if the window is no more active */
1929 if (hwnd == info.hwndActive)
1931 if (!info.hwndFocus || !hwnd || NtUserGetAncestor( info.hwndFocus, GA_ROOT ) != hwnd)
1932 set_focus_window( hwnd );
1936 return TRUE;
1939 /**********************************************************************
1940 * NtUserSetActiveWindow (win32u.@)
1942 HWND WINAPI NtUserSetActiveWindow( HWND hwnd )
1944 HWND prev;
1946 TRACE( "%p\n", hwnd );
1948 if (hwnd)
1950 LONG style;
1952 hwnd = get_full_window_handle( hwnd );
1953 if (!is_window( hwnd ))
1955 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE );
1956 return 0;
1959 style = get_window_long( hwnd, GWL_STYLE );
1960 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD)
1961 return get_active_window(); /* Windows doesn't seem to return an error here */
1964 if (!set_active_window( hwnd, &prev, FALSE, TRUE )) return 0;
1965 return prev;
1968 /*****************************************************************
1969 * NtUserSetFocus (win32u.@)
1971 HWND WINAPI NtUserSetFocus( HWND hwnd )
1973 HWND hwndTop = hwnd;
1974 HWND previous = get_focus();
1976 TRACE( "%p prev %p\n", hwnd, previous );
1978 if (hwnd)
1980 /* Check if we can set the focus to this window */
1981 hwnd = get_full_window_handle( hwnd );
1982 if (!is_window( hwnd ))
1984 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE );
1985 return 0;
1987 if (hwnd == previous) return previous; /* nothing to do */
1988 for (;;)
1990 HWND parent;
1991 LONG style = get_window_long( hwndTop, GWL_STYLE );
1992 if (style & (WS_MINIMIZE | WS_DISABLED)) return 0;
1993 if (!(style & WS_CHILD)) break;
1994 parent = NtUserGetAncestor( hwndTop, GA_PARENT );
1995 if (!parent || parent == get_desktop_window())
1997 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return 0;
1998 break;
2000 if (parent == get_hwnd_message_parent()) return 0;
2001 hwndTop = parent;
2004 /* call hooks */
2005 if (call_hooks( WH_CBT, HCBT_SETFOCUS, (WPARAM)hwnd, (LPARAM)previous, 0 )) return 0;
2007 /* activate hwndTop if needed. */
2008 if (hwndTop != get_active_window())
2010 if (!set_active_window( hwndTop, NULL, FALSE, FALSE )) return 0;
2011 if (!is_window( hwnd )) return 0; /* Abort if window destroyed */
2013 /* Do not change focus if the window is no longer active */
2014 if (hwndTop != get_active_window()) return 0;
2017 else /* NULL hwnd passed in */
2019 if (!previous) return 0; /* nothing to do */
2020 if (call_hooks( WH_CBT, HCBT_SETFOCUS, 0, (LPARAM)previous, 0 )) return 0;
2023 /* change focus and send messages */
2024 return set_focus_window( hwnd );
2027 /*******************************************************************
2028 * set_foreground_window
2030 BOOL set_foreground_window( HWND hwnd, BOOL mouse )
2032 BOOL ret, send_msg_old = FALSE, send_msg_new = FALSE;
2033 HWND previous = 0;
2035 if (mouse) hwnd = get_full_window_handle( hwnd );
2037 SERVER_START_REQ( set_foreground_window )
2039 req->handle = wine_server_user_handle( hwnd );
2040 if ((ret = !wine_server_call_err( req )))
2042 previous = wine_server_ptr_handle( reply->previous );
2043 send_msg_old = reply->send_msg_old;
2044 send_msg_new = reply->send_msg_new;
2047 SERVER_END_REQ;
2049 if (ret && previous != hwnd)
2051 if (send_msg_old) /* old window belongs to other thread */
2052 NtUserMessageCall( previous, WM_WINE_SETACTIVEWINDOW, 0, 0,
2053 0, NtUserSendNotifyMessage, FALSE );
2054 else if (send_msg_new) /* old window belongs to us but new one to other thread */
2055 ret = set_active_window( 0, NULL, mouse, TRUE );
2057 if (send_msg_new) /* new window belongs to other thread */
2058 NtUserMessageCall( hwnd, WM_WINE_SETACTIVEWINDOW, (WPARAM)hwnd, 0,
2059 0, NtUserSendNotifyMessage, FALSE );
2060 else /* new window belongs to us */
2061 ret = set_active_window( hwnd, NULL, mouse, TRUE );
2063 return ret;
2066 static struct
2068 HBITMAP bitmap;
2069 unsigned int timeout;
2070 } caret = {0, 500};
2072 static void display_caret( HWND hwnd, const RECT *r )
2074 HDC dc, mem_dc;
2076 /* do not use DCX_CACHE here, since coördinates are in logical units */
2077 if (!(dc = NtUserGetDCEx( hwnd, 0, DCX_USESTYLE )))
2078 return;
2079 mem_dc = NtGdiCreateCompatibleDC(dc);
2080 if (mem_dc)
2082 HBITMAP prev_bitmap;
2084 prev_bitmap = NtGdiSelectBitmap( mem_dc, caret.bitmap );
2085 NtGdiBitBlt( dc, r->left, r->top, r->right-r->left, r->bottom-r->top, mem_dc, 0, 0, SRCINVERT, 0, 0 );
2086 NtGdiSelectBitmap( mem_dc, prev_bitmap );
2087 NtGdiDeleteObjectApp( mem_dc );
2089 NtUserReleaseDC( hwnd, dc );
2092 static unsigned int get_caret_registry_timeout(void)
2094 char value_buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[11 * sizeof(WCHAR)])];
2095 KEY_VALUE_PARTIAL_INFORMATION *value = (void *)value_buffer;
2096 unsigned int ret = 500;
2097 HKEY key;
2099 if (!(key = reg_open_hkcu_key( "Control Panel\\Desktop" )))
2100 return ret;
2102 if (query_reg_ascii_value( key, "CursorBlinkRate", value, sizeof(value_buffer) ))
2103 ret = wcstoul( (WCHAR *)value->Data, NULL, 10 );
2104 NtClose( key );
2105 return ret;
2108 /*****************************************************************
2109 * NtUserCreateCaret (win32u.@)
2111 BOOL WINAPI NtUserCreateCaret( HWND hwnd, HBITMAP bitmap, int width, int height )
2113 HBITMAP caret_bitmap = 0;
2114 int old_state = 0;
2115 int hidden = 0;
2116 HWND prev = 0;
2117 BOOL ret;
2118 RECT r;
2120 TRACE( "hwnd %p, bitmap %p, width %d, height %d\n", hwnd, bitmap, width, height );
2122 if (!hwnd) return FALSE;
2124 if (bitmap && bitmap != (HBITMAP)1)
2126 BITMAP bitmap_data;
2128 if (!NtGdiExtGetObjectW( bitmap, sizeof(bitmap_data), &bitmap_data )) return FALSE;
2129 width = bitmap_data.bmWidth;
2130 height = bitmap_data.bmHeight;
2131 caret_bitmap = NtGdiCreateBitmap( bitmap_data.bmWidth, bitmap_data.bmHeight,
2132 bitmap_data.bmPlanes, bitmap_data.bmBitsPixel, NULL );
2133 if (caret_bitmap)
2135 size_t size = bitmap_data.bmWidthBytes * bitmap_data.bmHeight;
2136 BYTE *bits = malloc( size );
2138 NtGdiGetBitmapBits( bitmap, size, bits );
2139 NtGdiSetBitmapBits( caret_bitmap, size, bits );
2140 free( bits );
2143 else
2145 HDC dc;
2147 if (!width) width = get_system_metrics( SM_CXBORDER );
2148 if (!height) height = get_system_metrics( SM_CYBORDER );
2150 /* create the uniform bitmap on the fly */
2151 dc = NtUserGetDCEx( hwnd, 0, DCX_USESTYLE );
2152 if (dc)
2154 HDC mem_dc = NtGdiCreateCompatibleDC( dc );
2155 if (mem_dc)
2157 if ((caret_bitmap = NtGdiCreateCompatibleBitmap( mem_dc, width, height )))
2159 HBITMAP prev_bitmap = NtGdiSelectBitmap( mem_dc, caret_bitmap );
2160 SetRect( &r, 0, 0, width, height );
2161 fill_rect( mem_dc, &r, GetStockObject( bitmap ? GRAY_BRUSH : WHITE_BRUSH ));
2162 NtGdiSelectBitmap( mem_dc, prev_bitmap );
2164 NtGdiDeleteObjectApp( mem_dc );
2166 NtUserReleaseDC( hwnd, dc );
2169 if (!caret_bitmap) return FALSE;
2171 SERVER_START_REQ( set_caret_window )
2173 req->handle = wine_server_user_handle( hwnd );
2174 req->width = width;
2175 req->height = height;
2176 if ((ret = !wine_server_call_err( req )))
2178 prev = wine_server_ptr_handle( reply->previous );
2179 r.left = reply->old_rect.left;
2180 r.top = reply->old_rect.top;
2181 r.right = reply->old_rect.right;
2182 r.bottom = reply->old_rect.bottom;
2183 old_state = reply->old_state;
2184 hidden = reply->old_hide;
2187 SERVER_END_REQ;
2188 if (!ret) return FALSE;
2190 if (prev && !hidden) /* hide the previous one */
2192 /* FIXME: won't work if prev belongs to a different process */
2193 kill_system_timer( prev, SYSTEM_TIMER_CARET );
2194 if (old_state) display_caret( prev, &r );
2197 if (caret.bitmap) NtGdiDeleteObjectApp( caret.bitmap );
2198 caret.bitmap = caret_bitmap;
2199 caret.timeout = get_caret_registry_timeout();
2200 return TRUE;
2203 /*******************************************************************
2204 * destroy_caret
2206 BOOL destroy_caret(void)
2208 int old_state = 0;
2209 int hidden = 0;
2210 HWND prev = 0;
2211 BOOL ret;
2212 RECT r;
2214 SERVER_START_REQ( set_caret_window )
2216 req->handle = 0;
2217 req->width = 0;
2218 req->height = 0;
2219 if ((ret = !wine_server_call_err( req )))
2221 prev = wine_server_ptr_handle( reply->previous );
2222 r.left = reply->old_rect.left;
2223 r.top = reply->old_rect.top;
2224 r.right = reply->old_rect.right;
2225 r.bottom = reply->old_rect.bottom;
2226 old_state = reply->old_state;
2227 hidden = reply->old_hide;
2230 SERVER_END_REQ;
2232 if (ret && prev && !hidden)
2234 /* FIXME: won't work if prev belongs to a different process */
2235 kill_system_timer( prev, SYSTEM_TIMER_CARET );
2236 if (old_state) display_caret( prev, &r );
2238 if (caret.bitmap) NtGdiDeleteObjectApp( caret.bitmap );
2239 caret.bitmap = 0;
2240 return ret;
2243 /*****************************************************************
2244 * NtUserGetCaretBlinkTime (win32u.@)
2246 UINT WINAPI NtUserGetCaretBlinkTime(void)
2248 return caret.timeout;
2251 /*******************************************************************
2252 * set_caret_blink_time
2254 BOOL set_caret_blink_time( unsigned int time )
2256 TRACE( "time %u\n", time );
2258 caret.timeout = time;
2259 /* FIXME: update the timer */
2260 return TRUE;
2263 /*****************************************************************
2264 * NtUserGetCaretPos (win32u.@)
2266 BOOL WINAPI NtUserGetCaretPos( POINT *pt )
2268 BOOL ret;
2270 SERVER_START_REQ( set_caret_info )
2272 req->flags = 0; /* don't set anything */
2273 req->handle = 0;
2274 req->x = 0;
2275 req->y = 0;
2276 req->hide = 0;
2277 req->state = 0;
2278 if ((ret = !wine_server_call_err( req )))
2280 pt->x = reply->old_rect.left;
2281 pt->y = reply->old_rect.top;
2284 SERVER_END_REQ;
2285 return ret;
2288 /*******************************************************************
2289 * set_caret_pos
2291 BOOL set_caret_pos( int x, int y )
2293 int old_state = 0;
2294 int hidden = 0;
2295 HWND hwnd = 0;
2296 BOOL ret;
2297 RECT r;
2299 TRACE( "(%d, %d)\n", x, y );
2301 SERVER_START_REQ( set_caret_info )
2303 req->flags = SET_CARET_POS|SET_CARET_STATE;
2304 req->handle = 0;
2305 req->x = x;
2306 req->y = y;
2307 req->hide = 0;
2308 req->state = CARET_STATE_ON_IF_MOVED;
2309 if ((ret = !wine_server_call_err( req )))
2311 hwnd = wine_server_ptr_handle( reply->full_handle );
2312 r.left = reply->old_rect.left;
2313 r.top = reply->old_rect.top;
2314 r.right = reply->old_rect.right;
2315 r.bottom = reply->old_rect.bottom;
2316 old_state = reply->old_state;
2317 hidden = reply->old_hide;
2320 SERVER_END_REQ;
2321 if (ret && !hidden && (x != r.left || y != r.top))
2323 if (old_state) display_caret( hwnd, &r );
2324 r.right += x - r.left;
2325 r.bottom += y - r.top;
2326 r.left = x;
2327 r.top = y;
2328 display_caret( hwnd, &r );
2329 NtUserSetSystemTimer( hwnd, SYSTEM_TIMER_CARET, caret.timeout );
2331 return ret;
2334 /*****************************************************************
2335 * NtUserShowCaret (win32u.@)
2337 BOOL WINAPI NtUserShowCaret( HWND hwnd )
2339 int hidden = 0;
2340 BOOL ret;
2341 RECT r;
2343 SERVER_START_REQ( set_caret_info )
2345 req->flags = SET_CARET_HIDE | SET_CARET_STATE;
2346 req->handle = wine_server_user_handle( hwnd );
2347 req->x = 0;
2348 req->y = 0;
2349 req->hide = -1;
2350 req->state = CARET_STATE_ON;
2351 if ((ret = !wine_server_call_err( req )))
2353 hwnd = wine_server_ptr_handle( reply->full_handle );
2354 r.left = reply->old_rect.left;
2355 r.top = reply->old_rect.top;
2356 r.right = reply->old_rect.right;
2357 r.bottom = reply->old_rect.bottom;
2358 hidden = reply->old_hide;
2361 SERVER_END_REQ;
2363 if (ret && hidden == 1) /* hidden was 1 so it's now 0 */
2365 display_caret( hwnd, &r );
2366 NtUserSetSystemTimer( hwnd, SYSTEM_TIMER_CARET, caret.timeout );
2368 return ret;
2371 /*****************************************************************
2372 * NtUserHideCaret (win32u.@)
2374 BOOL WINAPI NtUserHideCaret( HWND hwnd )
2376 int old_state = 0;
2377 int hidden = 0;
2378 BOOL ret;
2379 RECT r;
2381 SERVER_START_REQ( set_caret_info )
2383 req->flags = SET_CARET_HIDE | SET_CARET_STATE;
2384 req->handle = wine_server_user_handle( hwnd );
2385 req->x = 0;
2386 req->y = 0;
2387 req->hide = 1;
2388 req->state = CARET_STATE_OFF;
2389 if ((ret = !wine_server_call_err( req )))
2391 hwnd = wine_server_ptr_handle( reply->full_handle );
2392 r.left = reply->old_rect.left;
2393 r.top = reply->old_rect.top;
2394 r.right = reply->old_rect.right;
2395 r.bottom = reply->old_rect.bottom;
2396 old_state = reply->old_state;
2397 hidden = reply->old_hide;
2400 SERVER_END_REQ;
2402 if (ret && !hidden)
2404 if (old_state) display_caret( hwnd, &r );
2405 kill_system_timer( hwnd, SYSTEM_TIMER_CARET );
2407 return ret;
2410 void toggle_caret( HWND hwnd )
2412 BOOL ret;
2413 RECT r;
2414 int hidden = 0;
2416 SERVER_START_REQ( set_caret_info )
2418 req->flags = SET_CARET_STATE;
2419 req->handle = wine_server_user_handle( hwnd );
2420 req->x = 0;
2421 req->y = 0;
2422 req->hide = 0;
2423 req->state = CARET_STATE_TOGGLE;
2424 if ((ret = !wine_server_call( req )))
2426 hwnd = wine_server_ptr_handle( reply->full_handle );
2427 r.left = reply->old_rect.left;
2428 r.top = reply->old_rect.top;
2429 r.right = reply->old_rect.right;
2430 r.bottom = reply->old_rect.bottom;
2431 hidden = reply->old_hide;
2434 SERVER_END_REQ;
2436 if (ret && !hidden) display_caret( hwnd, &r );
2440 /**********************************************************************
2441 * NtUserEnableMouseInPointer (win32u.@)
2443 BOOL WINAPI NtUserEnableMouseInPointer( BOOL enable )
2445 FIXME( "enable %u stub!\n", enable );
2446 RtlSetLastWin32Error( ERROR_CALL_NOT_IMPLEMENTED );
2447 return FALSE;
2450 /**********************************************************************
2451 * NtUserIsMouseInPointerEnabled (win32u.@)
2453 BOOL WINAPI NtUserIsMouseInPointerEnabled(void)
2455 FIXME( "stub!\n" );
2456 RtlSetLastWin32Error( ERROR_CALL_NOT_IMPLEMENTED );
2457 return FALSE;
2460 /**********************************************************************
2461 * NtUserGetPointerInfoList (win32u.@)
2463 BOOL WINAPI NtUserGetPointerInfoList( UINT32 id, POINTER_INPUT_TYPE type, UINT_PTR unk0, UINT_PTR unk1, SIZE_T size,
2464 UINT32 *entry_count, UINT32 *pointer_count, void *pointer_info )
2466 FIXME( "id %#x, type %#x, unk0 %#zx, unk1 %#zx, size %#zx, entry_count %p, pointer_count %p, pointer_info %p stub!\n",
2467 id, (int)type, (size_t)unk0, (size_t)unk1, (size_t)size, entry_count, pointer_count, pointer_info );
2468 RtlSetLastWin32Error( ERROR_CALL_NOT_IMPLEMENTED );
2469 return FALSE;
2472 HWND get_shell_window(void)
2474 HWND hwnd = 0;
2476 SERVER_START_REQ(set_global_windows)
2478 req->flags = 0;
2479 if (!wine_server_call_err(req))
2480 hwnd = wine_server_ptr_handle( reply->old_shell_window );
2482 SERVER_END_REQ;
2484 return hwnd;
2487 /***********************************************************************
2488 * NtUserSetShellWindowEx (win32u.@)
2490 BOOL WINAPI NtUserSetShellWindowEx( HWND shell, HWND list_view )
2492 BOOL ret;
2494 /* shell = Progman[Program Manager]
2495 * |-> SHELLDLL_DefView
2496 * list_view = | |-> SysListView32
2497 * | | |-> tooltips_class32
2498 * | |
2499 * | |-> SysHeader32
2501 * |-> ProxyTarget
2504 if (get_shell_window())
2505 return FALSE;
2507 if (get_window_long( shell, GWL_EXSTYLE ) & WS_EX_TOPMOST)
2508 return FALSE;
2510 if (list_view != shell && (get_window_long( list_view, GWL_EXSTYLE ) & WS_EX_TOPMOST))
2511 return FALSE;
2513 if (list_view && list_view != shell)
2514 NtUserSetWindowPos( list_view, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE );
2516 NtUserSetWindowPos( shell, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE );
2518 SERVER_START_REQ(set_global_windows)
2520 req->flags = SET_GLOBAL_SHELL_WINDOWS;
2521 req->shell_window = wine_server_user_handle( shell );
2522 req->shell_listview = wine_server_user_handle( list_view );
2523 ret = !wine_server_call_err(req);
2525 SERVER_END_REQ;
2526 return ret;
2529 HWND get_progman_window(void)
2531 HWND ret = 0;
2533 SERVER_START_REQ(set_global_windows)
2535 req->flags = 0;
2536 if (!wine_server_call_err(req))
2537 ret = wine_server_ptr_handle( reply->old_progman_window );
2539 SERVER_END_REQ;
2540 return ret;
2543 HWND set_progman_window( HWND hwnd )
2545 SERVER_START_REQ(set_global_windows)
2547 req->flags = SET_GLOBAL_PROGMAN_WINDOW;
2548 req->progman_window = wine_server_user_handle( hwnd );
2549 if (wine_server_call_err( req )) hwnd = 0;
2551 SERVER_END_REQ;
2552 return hwnd;
2555 HWND get_taskman_window(void)
2557 HWND ret = 0;
2559 SERVER_START_REQ(set_global_windows)
2561 req->flags = 0;
2562 if (!wine_server_call_err(req))
2563 ret = wine_server_ptr_handle( reply->old_taskman_window );
2565 SERVER_END_REQ;
2566 return ret;
2569 HWND set_taskman_window( HWND hwnd )
2571 /* hwnd = MSTaskSwWClass
2572 * |-> SysTabControl32
2574 SERVER_START_REQ(set_global_windows)
2576 req->flags = SET_GLOBAL_TASKMAN_WINDOW;
2577 req->taskman_window = wine_server_user_handle( hwnd );
2578 if (wine_server_call_err( req )) hwnd = 0;
2580 SERVER_END_REQ;
2581 return hwnd;