msxml4/tests: Copy namespaces as attributes tests.
[wine.git] / dlls / win32u / input.c
blob3e6e440de9318a37b74fceaf9cabf2dbb8fd2a48
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),
407 static LONG clipping_cursor; /* clipping thread counter */
409 LONG global_key_state_counter = 0;
410 BOOL grab_pointer = TRUE;
411 BOOL grab_fullscreen = FALSE;
413 static void kbd_tables_init_vsc2vk( const KBDTABLES *tables, BYTE vsc2vk[0x300] )
415 const VSC_VK *entry;
416 WORD vsc;
418 memset( vsc2vk, 0, 0x300 );
420 for (vsc = 0; tables->pusVSCtoVK && vsc <= tables->bMaxVSCtoVK; ++vsc)
422 if (tables->pusVSCtoVK[vsc] == VK__none_) continue;
423 vsc2vk[vsc] = (BYTE)tables->pusVSCtoVK[vsc];
425 for (entry = tables->pVSCtoVK_E0; entry && entry->Vsc; entry++)
427 if (entry->Vk == VK__none_) continue;
428 vsc2vk[entry->Vsc + 0x100] = (BYTE)entry->Vk;
430 for (entry = tables->pVSCtoVK_E1; entry && entry->Vsc; entry++)
432 if (entry->Vk == VK__none_) continue;
433 vsc2vk[entry->Vsc + 0x200] = (BYTE)entry->Vk;
437 #define NEXT_ENTRY(t, e) ((void *)&(e)->wch[(t)->nModifications])
439 static void kbd_tables_init_vk2char( const KBDTABLES *tables, BYTE vk2char[0x100] )
441 const VK_TO_WCHAR_TABLE *table;
442 const VK_TO_WCHARS1 *entry;
444 memset( vk2char, 0, 0x100 );
446 for (table = tables->pVkToWcharTable; table->pVkToWchars; table++)
448 for (entry = table->pVkToWchars; entry->VirtualKey; entry = NEXT_ENTRY(table, entry))
450 if (entry->VirtualKey & ~0xff) continue;
451 vk2char[entry->VirtualKey] = entry->wch[0];
456 static UINT kbd_tables_get_mod_bits( const KBDTABLES *tables, UINT mod )
458 const MODIFIERS *mods = tables->pCharModifiers;
459 WORD bits;
461 for (bits = 0; bits <= mods->wMaxModBits; ++bits)
462 if (mods->ModNumber[bits] == mod) return bits;
464 return -1;
467 static UINT kbd_tables_get_mod_num( const KBDTABLES *tables, const BYTE *state, BOOL caps )
469 const MODIFIERS *mods = tables->pCharModifiers;
470 const VK_TO_BIT *entry;
471 WORD bits = 0;
473 for (entry = mods->pVkToBit; entry->Vk; ++entry)
474 if (state[entry->Vk] & 0x80) bits |= entry->ModBits;
475 if (caps) bits |= KBDSHIFT;
477 if (bits > mods->wMaxModBits) return -1;
478 return mods->ModNumber[bits];
481 static WORD kbd_tables_wchar_to_vkey( const KBDTABLES *tables, WCHAR wch )
483 const VK_TO_WCHAR_TABLE *table;
484 const VK_TO_WCHARS1 *entry;
485 WORD bits;
486 BYTE mod;
488 if (wch == '\x001b') return VK_ESCAPE;
490 for (table = tables->pVkToWcharTable; table->pVkToWchars; table++)
492 for (entry = table->pVkToWchars; entry->VirtualKey; entry = NEXT_ENTRY(table, entry))
494 for (mod = 0; mod < table->nModifications; ++mod)
496 if (entry->wch[mod] == WCH_NONE || entry->wch[mod] != wch) continue;
497 bits = kbd_tables_get_mod_bits( tables, mod );
498 return (bits << 8) | entry->VirtualKey;
503 if (wch >= 0x0001 && wch <= 0x001a) return (0x200) | ('A' + wch - 1); /* CTRL + A-Z */
504 return wch >= 0x0080 ? -1 : 0;
507 static WCHAR kbd_tables_vkey_to_wchar( const KBDTABLES *tables, UINT vkey, const BYTE *state )
509 UINT mod, caps_mod, alt, ctrl, caps;
510 const VK_TO_WCHAR_TABLE *table;
511 const VK_TO_WCHARS1 *entry;
513 alt = state[VK_MENU] & 0x80;
514 ctrl = state[VK_CONTROL] & 0x80;
515 caps = state[VK_CAPITAL] & 1;
517 if (ctrl && alt) return WCH_NONE;
518 if (!ctrl && vkey == VK_ESCAPE) return VK_ESCAPE;
520 mod = caps_mod = kbd_tables_get_mod_num( tables, state, FALSE );
521 if (caps) caps_mod = kbd_tables_get_mod_num( tables, state, TRUE );
523 for (table = tables->pVkToWcharTable; table->pVkToWchars; table++)
525 if (table->nModifications <= mod) continue;
526 for (entry = table->pVkToWchars; entry->VirtualKey; entry = NEXT_ENTRY(table, entry))
528 if (entry->VirtualKey != vkey) continue;
529 if ((entry->Attributes & CAPLOK) && table->nModifications > caps_mod) return entry->wch[caps_mod];
530 return entry->wch[mod];
534 if (ctrl && vkey >= 'A' && vkey <= 'Z') return vkey - 'A' + 1;
535 return WCH_NONE;
538 #undef NEXT_ENTRY
540 /*******************************************************************
541 * NtUserGetForegroundWindow (win32u.@)
543 HWND WINAPI NtUserGetForegroundWindow(void)
545 HWND ret = 0;
547 SERVER_START_REQ( get_thread_input )
549 req->tid = 0;
550 if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->foreground );
552 SERVER_END_REQ;
553 return ret;
556 /* see GetActiveWindow */
557 HWND get_active_window(void)
559 GUITHREADINFO info;
560 info.cbSize = sizeof(info);
561 return NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info ) ? info.hwndActive : 0;
564 /* see GetCapture */
565 HWND get_capture(void)
567 GUITHREADINFO info;
568 info.cbSize = sizeof(info);
569 return NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info ) ? info.hwndCapture : 0;
572 /* see GetFocus */
573 HWND get_focus(void)
575 GUITHREADINFO info;
576 info.cbSize = sizeof(info);
577 return NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info ) ? info.hwndFocus : 0;
580 /**********************************************************************
581 * NtUserAttachThreadInput (win32u.@)
583 BOOL WINAPI NtUserAttachThreadInput( DWORD from, DWORD to, BOOL attach )
585 BOOL ret;
587 SERVER_START_REQ( attach_thread_input )
589 req->tid_from = from;
590 req->tid_to = to;
591 req->attach = attach;
592 ret = !wine_server_call_err( req );
594 SERVER_END_REQ;
595 return ret;
598 /***********************************************************************
599 * __wine_send_input (win32u.@)
601 * Internal SendInput function to allow the graphics driver to inject real events.
603 BOOL WINAPI __wine_send_input( HWND hwnd, const INPUT *input, const RAWINPUT *rawinput )
605 return set_ntstatus( send_hardware_message( hwnd, input, rawinput, 0 ));
608 /***********************************************************************
609 * update_mouse_coords
611 * Helper for NtUserSendInput.
613 static void update_mouse_coords( INPUT *input )
615 if (!(input->mi.dwFlags & MOUSEEVENTF_MOVE)) return;
617 if (input->mi.dwFlags & MOUSEEVENTF_ABSOLUTE)
619 RECT rc;
621 if (input->mi.dwFlags & MOUSEEVENTF_VIRTUALDESK)
622 rc = get_virtual_screen_rect( 0 );
623 else
624 rc = get_primary_monitor_rect( 0 );
626 input->mi.dx = rc.left + ((input->mi.dx * (rc.right - rc.left)) >> 16);
627 input->mi.dy = rc.top + ((input->mi.dy * (rc.bottom - rc.top)) >> 16);
629 else
631 int accel[3];
633 /* dx and dy can be negative numbers for relative movements */
634 NtUserSystemParametersInfo( SPI_GETMOUSE, 0, accel, 0 );
636 if (!accel[2]) return;
638 if (abs( input->mi.dx ) > accel[0])
640 input->mi.dx *= 2;
641 if (abs( input->mi.dx ) > accel[1] && accel[2] == 2) input->mi.dx *= 2;
643 if (abs(input->mi.dy) > accel[0])
645 input->mi.dy *= 2;
646 if (abs( input->mi.dy ) > accel[1] && accel[2] == 2) input->mi.dy *= 2;
651 /***********************************************************************
652 * NtUserSendInput (win32u.@)
654 UINT WINAPI NtUserSendInput( UINT count, INPUT *inputs, int size )
656 UINT i;
657 NTSTATUS status = STATUS_SUCCESS;
659 if (size != sizeof(INPUT))
661 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
662 return 0;
665 if (!count)
667 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
668 return 0;
671 if (!inputs)
673 RtlSetLastWin32Error( ERROR_NOACCESS );
674 return 0;
677 for (i = 0; i < count; i++)
679 INPUT input = inputs[i];
680 switch (input.type)
682 case INPUT_MOUSE:
683 /* we need to update the coordinates to what the server expects */
684 update_mouse_coords( &input );
685 /* fallthrough */
686 case INPUT_KEYBOARD:
687 status = send_hardware_message( 0, &input, NULL, SEND_HWMSG_INJECTED );
688 break;
689 case INPUT_HARDWARE:
690 RtlSetLastWin32Error( ERROR_CALL_NOT_IMPLEMENTED );
691 return 0;
694 if (status)
696 RtlSetLastWin32Error( RtlNtStatusToDosError(status) );
697 break;
701 return i;
704 /***********************************************************************
705 * NtUserSetCursorPos (win32u.@)
707 BOOL WINAPI NtUserSetCursorPos( INT x, INT y )
709 POINT pt = { x, y };
710 BOOL ret;
711 INT prev_x, prev_y, new_x, new_y;
712 UINT dpi;
714 if ((dpi = get_thread_dpi()))
716 HMONITOR monitor = monitor_from_point( pt, MONITOR_DEFAULTTOPRIMARY, get_thread_dpi() );
717 pt = map_dpi_point( pt, dpi, get_monitor_dpi( monitor ));
720 SERVER_START_REQ( set_cursor )
722 req->flags = SET_CURSOR_POS;
723 req->x = pt.x;
724 req->y = pt.y;
725 if ((ret = !wine_server_call( req )))
727 prev_x = reply->prev_x;
728 prev_y = reply->prev_y;
729 new_x = reply->new_x;
730 new_y = reply->new_y;
733 SERVER_END_REQ;
734 if (ret && (prev_x != new_x || prev_y != new_y)) user_driver->pSetCursorPos( new_x, new_y );
735 return ret;
738 /***********************************************************************
739 * get_cursor_pos
741 BOOL get_cursor_pos( POINT *pt )
743 BOOL ret;
744 DWORD last_change;
745 UINT dpi;
747 if (!pt) return FALSE;
749 SERVER_START_REQ( set_cursor )
751 if ((ret = !wine_server_call( req )))
753 pt->x = reply->new_x;
754 pt->y = reply->new_y;
755 last_change = reply->last_change;
758 SERVER_END_REQ;
760 /* query new position from graphics driver if we haven't updated recently */
761 if (ret && NtGetTickCount() - last_change > 100) ret = user_driver->pGetCursorPos( pt );
762 if (ret && (dpi = get_thread_dpi()))
764 HMONITOR monitor = monitor_from_point( *pt, MONITOR_DEFAULTTOPRIMARY, 0 );
765 *pt = map_dpi_point( *pt, get_monitor_dpi( monitor ), dpi );
767 return ret;
770 /***********************************************************************
771 * NtUserGetCursorInfo (win32u.@)
773 BOOL WINAPI NtUserGetCursorInfo( CURSORINFO *info )
775 BOOL ret;
777 if (!info) return FALSE;
779 SERVER_START_REQ( get_thread_input )
781 req->tid = 0;
782 if ((ret = !wine_server_call( req )))
784 info->hCursor = wine_server_ptr_handle( reply->cursor );
785 info->flags = reply->show_count >= 0 ? CURSOR_SHOWING : 0;
788 SERVER_END_REQ;
789 get_cursor_pos( &info->ptScreenPos );
790 return ret;
793 static void check_for_events( UINT flags )
795 if (!user_driver->pProcessEvents( flags ))
796 flush_window_surfaces( TRUE );
799 /**********************************************************************
800 * GetAsyncKeyState (win32u.@)
802 SHORT WINAPI NtUserGetAsyncKeyState( INT key )
804 struct user_key_state_info *key_state_info = get_user_thread_info()->key_state;
805 INT counter = global_key_state_counter;
806 BYTE prev_key_state;
807 SHORT ret;
809 if (key < 0 || key >= 256) return 0;
811 check_for_events( QS_INPUT );
813 if (key_state_info && !(key_state_info->state[key] & 0xc0) &&
814 key_state_info->counter == counter && NtGetTickCount() - key_state_info->time < 50)
816 /* use cached value */
817 return 0;
819 else if (!key_state_info)
821 key_state_info = calloc( 1, sizeof(*key_state_info) );
822 get_user_thread_info()->key_state = key_state_info;
825 ret = 0;
826 SERVER_START_REQ( get_key_state )
828 req->async = 1;
829 req->key = key;
830 if (key_state_info)
832 prev_key_state = key_state_info->state[key];
833 wine_server_set_reply( req, key_state_info->state, sizeof(key_state_info->state) );
835 if (!wine_server_call( req ))
837 if (reply->state & 0x40) ret |= 0x0001;
838 if (reply->state & 0x80) ret |= 0x8000;
839 if (key_state_info)
841 /* force refreshing the key state cache - some multithreaded programs
842 * (like Adobe Photoshop CS5) expect that changes to the async key state
843 * are also immediately available in other threads. */
844 if (prev_key_state != key_state_info->state[key])
845 counter = InterlockedIncrement( &global_key_state_counter );
847 key_state_info->time = NtGetTickCount();
848 key_state_info->counter = counter;
852 SERVER_END_REQ;
854 return ret;
857 /***********************************************************************
858 * NtUserGetQueueStatus (win32u.@)
860 DWORD WINAPI NtUserGetQueueStatus( UINT flags )
862 DWORD ret;
864 if (flags & ~(QS_ALLINPUT | QS_ALLPOSTMESSAGE | QS_SMRESULT))
866 RtlSetLastWin32Error( ERROR_INVALID_FLAGS );
867 return 0;
870 check_for_events( flags );
872 SERVER_START_REQ( get_queue_status )
874 req->clear_bits = flags;
875 wine_server_call( req );
876 ret = MAKELONG( reply->changed_bits & flags, reply->wake_bits & flags );
878 SERVER_END_REQ;
879 return ret;
882 /***********************************************************************
883 * get_input_state
885 DWORD get_input_state(void)
887 DWORD ret;
889 check_for_events( QS_INPUT );
891 SERVER_START_REQ( get_queue_status )
893 req->clear_bits = 0;
894 wine_server_call( req );
895 ret = reply->wake_bits & (QS_KEY | QS_MOUSEBUTTON);
897 SERVER_END_REQ;
898 return ret;
901 /***********************************************************************
902 * get_locale_kbd_layout
904 static HKL get_locale_kbd_layout(void)
906 LCID layout;
907 LANGID langid;
909 /* FIXME:
911 * layout = main_key_tab[kbd_layout].lcid;
913 * Winword uses return value of GetKeyboardLayout as a codepage
914 * to translate ANSI keyboard messages to unicode. But we have
915 * a problem with it: for instance Polish keyboard layout is
916 * identical to the US one, and therefore instead of the Polish
917 * locale id we return the US one.
920 NtQueryDefaultLocale( TRUE, &layout );
923 * Microsoft Office expects this value to be something specific
924 * for Japanese and Korean Windows with an IME the value is 0xe001
925 * We should probably check to see if an IME exists and if so then
926 * set this word properly.
928 langid = PRIMARYLANGID( LANGIDFROMLCID( layout ) );
929 if (langid == LANG_CHINESE || langid == LANG_JAPANESE || langid == LANG_KOREAN)
930 layout = MAKELONG( layout, 0xe001 ); /* IME */
931 else
932 layout = MAKELONG( layout, layout );
934 return ULongToHandle( layout );
937 /***********************************************************************
938 * NtUserGetKeyboardLayout (win32u.@)
940 * Device handle for keyboard layout defaulted to
941 * the language id. This is the way Windows default works.
943 HKL WINAPI NtUserGetKeyboardLayout( DWORD thread_id )
945 struct user_thread_info *thread = get_user_thread_info();
946 HKL layout = thread->kbd_layout;
948 if (thread_id && thread_id != GetCurrentThreadId())
949 FIXME( "couldn't return keyboard layout for thread %04x\n", (int)thread_id );
951 if (!layout) return get_locale_kbd_layout();
952 return layout;
955 /**********************************************************************
956 * NtUserGetKeyState (win32u.@)
958 * An application calls the GetKeyState function in response to a
959 * keyboard-input message. This function retrieves the state of the key
960 * at the time the input message was generated.
962 SHORT WINAPI NtUserGetKeyState( INT vkey )
964 SHORT retval = 0;
966 SERVER_START_REQ( get_key_state )
968 req->key = vkey;
969 if (!wine_server_call( req )) retval = (signed char)(reply->state & 0x81);
971 SERVER_END_REQ;
972 TRACE("key (0x%x) -> %x\n", vkey, retval);
973 return retval;
976 /**********************************************************************
977 * NtUserGetKeyboardState (win32u.@)
979 BOOL WINAPI NtUserGetKeyboardState( BYTE *state )
981 BOOL ret;
982 UINT i;
984 TRACE("(%p)\n", state);
986 memset( state, 0, 256 );
987 SERVER_START_REQ( get_key_state )
989 req->key = -1;
990 wine_server_set_reply( req, state, 256 );
991 ret = !wine_server_call_err( req );
992 for (i = 0; i < 256; i++) state[i] &= 0x81;
994 SERVER_END_REQ;
995 return ret;
998 /**********************************************************************
999 * NtUserSetKeyboardState (win32u.@)
1001 BOOL WINAPI NtUserSetKeyboardState( BYTE *state )
1003 BOOL ret;
1005 SERVER_START_REQ( set_key_state )
1007 wine_server_add_data( req, state, 256 );
1008 ret = !wine_server_call_err( req );
1010 SERVER_END_REQ;
1011 return ret;
1014 /******************************************************************************
1015 * NtUserVkKeyScanEx (win32u.@)
1017 WORD WINAPI NtUserVkKeyScanEx( WCHAR chr, HKL layout )
1019 const KBDTABLES *kbd_tables = &kbdus_tables;
1020 SHORT ret;
1022 TRACE_(keyboard)( "chr %s, layout %p\n", debugstr_wn(&chr, 1), layout );
1024 if ((ret = user_driver->pVkKeyScanEx( chr, layout )) != -256) return ret;
1025 ret = kbd_tables_wchar_to_vkey( kbd_tables, chr );
1027 TRACE_(keyboard)( "ret %04x\n", ret );
1028 return ret;
1032 /******************************************************************************
1033 * NtUserMapVirtualKeyEx (win32u.@)
1035 UINT WINAPI NtUserMapVirtualKeyEx( UINT code, UINT type, HKL layout )
1037 const KBDTABLES *kbd_tables = &kbdus_tables;
1038 BYTE vsc2vk[0x300], vk2char[0x100];
1039 UINT ret;
1041 TRACE_(keyboard)( "code %u, type %u, layout %p.\n", code, type, layout );
1043 if ((ret = user_driver->pMapVirtualKeyEx( code, type, layout )) != -1) return ret;
1045 switch (type)
1047 case MAPVK_VK_TO_VSC_EX:
1048 case MAPVK_VK_TO_VSC:
1049 switch (code)
1051 case VK_SHIFT: code = VK_LSHIFT; break;
1052 case VK_CONTROL: code = VK_LCONTROL; break;
1053 case VK_MENU: code = VK_LMENU; break;
1054 case VK_NUMPAD0: code = VK_INSERT; break;
1055 case VK_NUMPAD1: code = VK_END; break;
1056 case VK_NUMPAD2: code = VK_DOWN; break;
1057 case VK_NUMPAD3: code = VK_NEXT; break;
1058 case VK_NUMPAD4: code = VK_LEFT; break;
1059 case VK_NUMPAD5: code = VK_CLEAR; break;
1060 case VK_NUMPAD6: code = VK_RIGHT; break;
1061 case VK_NUMPAD7: code = VK_HOME; break;
1062 case VK_NUMPAD8: code = VK_UP; break;
1063 case VK_NUMPAD9: code = VK_PRIOR; break;
1064 case VK_DECIMAL: code = VK_DELETE; break;
1067 kbd_tables_init_vsc2vk( kbd_tables, vsc2vk );
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 kbd_tables_init_vsc2vk( kbd_tables, vsc2vk );
1082 if (code & 0xe000) code -= 0xdf00;
1083 if (code >= ARRAY_SIZE(vsc2vk)) ret = 0;
1084 else ret = vsc2vk[code];
1086 if (type == MAPVK_VSC_TO_VK)
1088 switch (ret)
1090 case VK_LSHIFT: case VK_RSHIFT: ret = VK_SHIFT; break;
1091 case VK_LCONTROL: case VK_RCONTROL: ret = VK_CONTROL; break;
1092 case VK_LMENU: case VK_RMENU: ret = VK_MENU; break;
1095 break;
1096 case MAPVK_VK_TO_CHAR:
1097 kbd_tables_init_vk2char( kbd_tables, vk2char );
1098 if (code >= ARRAY_SIZE(vk2char)) ret = 0;
1099 else if (code >= 'A' && code <= 'Z') ret = code;
1100 else ret = vk2char[code];
1101 break;
1102 default:
1103 FIXME_(keyboard)( "unknown type %d\n", type );
1104 return 0;
1107 TRACE_(keyboard)( "returning 0x%04x\n", ret );
1108 return ret;
1111 /****************************************************************************
1112 * NtUserGetKeyNameText (win32u.@)
1114 INT WINAPI NtUserGetKeyNameText( LONG lparam, WCHAR *buffer, INT size )
1116 INT code = ((lparam >> 16) & 0x1ff), vkey, len;
1117 const KBDTABLES *kbd_tables = &kbdus_tables;
1118 VSC_LPWSTR *key_name;
1120 TRACE_(keyboard)( "lparam %#x, buffer %p, size %d.\n", (int)lparam, buffer, size );
1122 if (!buffer || !size) return 0;
1123 if ((len = user_driver->pGetKeyNameText( lparam, buffer, size )) >= 0) return len;
1125 if (lparam & 0x2000000)
1127 BYTE vsc2vk[0x300];
1128 kbd_tables_init_vsc2vk( kbd_tables, vsc2vk );
1129 switch ((vkey = vsc2vk[code]))
1131 case VK_RSHIFT:
1132 case VK_RCONTROL:
1133 case VK_RMENU:
1134 for (code = 0; code < ARRAY_SIZE(vsc2vk); ++code)
1135 if (vsc2vk[code] == (vkey - 1)) break;
1136 break;
1140 if (code < 0x100) key_name = kbd_tables->pKeyNames;
1141 else key_name = kbd_tables->pKeyNamesExt;
1142 while (key_name->vsc && key_name->vsc != (BYTE)code) key_name++;
1144 if (key_name->vsc == (BYTE)code)
1146 len = min( size - 1, wcslen( key_name->pwsz ) );
1147 memcpy( buffer, key_name->pwsz, len * sizeof(WCHAR) );
1149 else if (size > 1)
1151 HKL hkl = NtUserGetKeyboardLayout( 0 );
1152 vkey = NtUserMapVirtualKeyEx( code & 0xff, MAPVK_VSC_TO_VK, hkl );
1153 buffer[0] = NtUserMapVirtualKeyEx( vkey, MAPVK_VK_TO_CHAR, hkl );
1154 len = 1;
1156 buffer[len] = 0;
1158 TRACE_(keyboard)( "ret %d, str %s.\n", len, debugstr_w(buffer) );
1159 return len;
1162 /****************************************************************************
1163 * NtUserToUnicodeEx (win32u.@)
1165 INT WINAPI NtUserToUnicodeEx( UINT virt, UINT scan, const BYTE *state,
1166 WCHAR *str, int size, UINT flags, HKL layout )
1168 const KBDTABLES *kbd_tables = &kbdus_tables;
1169 WCHAR buffer[2] = {0};
1170 INT len;
1172 TRACE_(keyboard)( "virt %#x, scan %#x, state %p, str %p, size %d, flags %#x, layout %p.\n",
1173 virt, scan, state, str, size, flags, layout );
1175 if (!state) return 0;
1176 if ((len = user_driver->pToUnicodeEx( virt, scan, state, str, size, flags, layout )) >= -1)
1177 return len;
1179 if (scan & 0x8000) buffer[0] = 0; /* key up */
1180 else buffer[0] = kbd_tables_vkey_to_wchar( kbd_tables, virt, state );
1182 if (buffer[0] != WCH_NONE) len = 1;
1183 else buffer[0] = len = 0;
1185 lstrcpynW( str, buffer, size );
1187 TRACE_(keyboard)( "ret %d, str %s.\n", len, debugstr_w(str) );
1188 return len;
1191 /**********************************************************************
1192 * NtUserActivateKeyboardLayout (win32u.@)
1194 HKL WINAPI NtUserActivateKeyboardLayout( HKL layout, UINT flags )
1196 struct user_thread_info *info = get_user_thread_info();
1197 HKL old_layout;
1198 LCID locale;
1199 HWND focus;
1201 TRACE_(keyboard)( "layout %p, flags %x\n", layout, flags );
1203 if (flags) FIXME_(keyboard)( "flags %x not supported\n", flags );
1205 if (layout == (HKL)HKL_NEXT || layout == (HKL)HKL_PREV)
1207 RtlSetLastWin32Error( ERROR_CALL_NOT_IMPLEMENTED );
1208 FIXME_(keyboard)( "HKL_NEXT and HKL_PREV not supported\n" );
1209 return 0;
1212 if (LOWORD(layout) != MAKELANGID(LANG_INVARIANT, SUBLANG_DEFAULT) &&
1213 (NtQueryDefaultLocale( TRUE, &locale ) || LOWORD(layout) != locale))
1215 RtlSetLastWin32Error( ERROR_CALL_NOT_IMPLEMENTED );
1216 FIXME_(keyboard)( "Changing user locale is not supported\n" );
1217 return 0;
1220 if (!user_driver->pActivateKeyboardLayout( layout, flags ))
1221 return 0;
1223 old_layout = info->kbd_layout;
1224 if (old_layout != layout)
1226 HWND ime_hwnd = get_default_ime_window( 0 );
1227 const NLS_LOCALE_DATA *data;
1228 CHARSETINFO cs = {0};
1230 if (ime_hwnd) send_message( ime_hwnd, WM_IME_INTERNAL, IME_INTERNAL_HKL_DEACTIVATE, HandleToUlong(old_layout) );
1232 if (HIWORD(layout) & 0x8000)
1233 FIXME( "Aliased keyboard layout not yet implemented\n" );
1234 else if (!(data = get_locale_data( HIWORD(layout) )))
1235 WARN( "Failed to find locale data for %04x\n", HIWORD(layout) );
1236 else
1237 translate_charset_info( ULongToPtr(data->idefaultansicodepage), &cs, TCI_SRCCODEPAGE );
1239 info->kbd_layout = layout;
1240 info->kbd_layout_id = 0;
1242 if (ime_hwnd) send_message( ime_hwnd, WM_IME_INTERNAL, IME_INTERNAL_HKL_ACTIVATE, HandleToUlong(layout) );
1244 if ((focus = get_focus()) && get_window_thread( focus, NULL ) == GetCurrentThreadId())
1245 send_message( focus, WM_INPUTLANGCHANGE, cs.ciCharset, (LPARAM)layout );
1248 if (!old_layout) return get_locale_kbd_layout();
1249 return old_layout;
1254 /***********************************************************************
1255 * NtUserGetKeyboardLayoutList (win32u.@)
1257 * Return number of values available if either input parm is
1258 * 0, per MS documentation.
1260 UINT WINAPI NtUserGetKeyboardLayoutList( INT size, HKL *layouts )
1262 char buffer[4096];
1263 KEY_NODE_INFORMATION *key_info = (KEY_NODE_INFORMATION *)buffer;
1264 KEY_VALUE_PARTIAL_INFORMATION *value_info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1265 DWORD count, tmp, i = 0;
1266 HKEY hkey, subkey;
1267 HKL layout;
1269 TRACE_(keyboard)( "size %d, layouts %p.\n", size, layouts );
1271 if ((count = user_driver->pGetKeyboardLayoutList( size, layouts )) != ~0) return count;
1273 layout = get_locale_kbd_layout();
1274 count = 0;
1276 count++;
1277 if (size && layouts)
1279 layouts[count - 1] = layout;
1280 if (count == size) return count;
1283 if ((hkey = reg_open_key( NULL, keyboard_layouts_keyW, sizeof(keyboard_layouts_keyW) )))
1285 while (!NtEnumerateKey( hkey, i++, KeyNodeInformation, key_info,
1286 sizeof(buffer) - sizeof(WCHAR), &tmp ))
1288 if (!(subkey = reg_open_key( hkey, key_info->Name, key_info->NameLength ))) continue;
1289 key_info->Name[key_info->NameLength / sizeof(WCHAR)] = 0;
1290 tmp = wcstoul( key_info->Name, NULL, 16 );
1291 if (query_reg_ascii_value( subkey, "Layout Id", value_info, sizeof(buffer) ) &&
1292 value_info->Type == REG_SZ)
1293 tmp = 0xf000 | (wcstoul( (const WCHAR *)value_info->Data, NULL, 16 ) & 0xfff);
1294 NtClose( subkey );
1296 tmp = MAKELONG( LOWORD( layout ), LOWORD( tmp ) );
1297 if (layout == UlongToHandle( tmp )) continue;
1299 count++;
1300 if (size && layouts)
1302 layouts[count - 1] = UlongToHandle( tmp );
1303 if (count == size) break;
1306 NtClose( hkey );
1309 return count;
1312 /****************************************************************************
1313 * NtUserGetKeyboardLayoutName (win32u.@)
1315 BOOL WINAPI NtUserGetKeyboardLayoutName( WCHAR *name )
1317 struct user_thread_info *info = get_user_thread_info();
1318 char buffer[4096];
1319 KEY_NODE_INFORMATION *key = (KEY_NODE_INFORMATION *)buffer;
1320 KEY_VALUE_PARTIAL_INFORMATION *value = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
1321 WCHAR klid[KL_NAMELENGTH];
1322 UINT id;
1323 ULONG len, i = 0;
1324 HKEY hkey, subkey;
1325 HKL layout;
1327 TRACE_(keyboard)( "name %p\n", name );
1329 if (!name)
1331 RtlSetLastWin32Error( ERROR_NOACCESS );
1332 return FALSE;
1335 if (info->kbd_layout_id)
1337 sprintf( buffer, "%08X", info->kbd_layout_id );
1338 asciiz_to_unicode( name, buffer );
1339 return TRUE;
1342 layout = NtUserGetKeyboardLayout( 0 );
1343 id = HandleToUlong( layout );
1344 if (HIWORD( id ) == LOWORD( id )) id = LOWORD( id );
1345 sprintf( buffer, "%08X", id );
1346 asciiz_to_unicode( name, buffer );
1348 if ((hkey = reg_open_key( NULL, keyboard_layouts_keyW, sizeof(keyboard_layouts_keyW) )))
1350 while (!NtEnumerateKey( hkey, i++, KeyNodeInformation, key,
1351 sizeof(buffer) - sizeof(WCHAR), &len ))
1353 if (!(subkey = reg_open_key( hkey, key->Name, key->NameLength ))) continue;
1354 memcpy( klid, key->Name, key->NameLength );
1355 klid[key->NameLength / sizeof(WCHAR)] = 0;
1356 if (query_reg_ascii_value( subkey, "Layout Id", value, sizeof(buffer) ) &&
1357 value->Type == REG_SZ)
1358 id = 0xf000 | (wcstoul( (const WCHAR *)value->Data, NULL, 16 ) & 0xfff);
1359 else
1360 id = wcstoul( klid, NULL, 16 );
1361 NtClose( subkey );
1363 if (HIWORD( layout ) == id)
1365 lstrcpynW( name, klid, KL_NAMELENGTH );
1366 break;
1369 NtClose( hkey );
1372 info->kbd_layout_id = wcstoul( name, NULL, 16 );
1374 TRACE_(keyboard)( "ret %s\n", debugstr_w( name ) );
1375 return TRUE;
1378 /***********************************************************************
1379 * NtUserRegisterHotKey (win32u.@)
1381 BOOL WINAPI NtUserRegisterHotKey( HWND hwnd, INT id, UINT modifiers, UINT vk )
1383 BOOL ret;
1384 int replaced = 0;
1386 TRACE_(keyboard)( "(%p,%d,0x%08x,%X)\n", hwnd, id, modifiers, vk );
1388 if ((!hwnd || is_current_thread_window( hwnd )) &&
1389 !user_driver->pRegisterHotKey( hwnd, modifiers, vk ))
1390 return FALSE;
1392 SERVER_START_REQ( register_hotkey )
1394 req->window = wine_server_user_handle( hwnd );
1395 req->id = id;
1396 req->flags = modifiers;
1397 req->vkey = vk;
1398 if ((ret = !wine_server_call_err( req )))
1400 replaced = reply->replaced;
1401 modifiers = reply->flags;
1402 vk = reply->vkey;
1405 SERVER_END_REQ;
1407 if (ret && replaced)
1408 user_driver->pUnregisterHotKey(hwnd, modifiers, vk);
1410 return ret;
1413 /***********************************************************************
1414 * NtUserUnregisterHotKey (win32u.@)
1416 BOOL WINAPI NtUserUnregisterHotKey( HWND hwnd, INT id )
1418 BOOL ret;
1419 UINT modifiers, vk;
1421 TRACE_(keyboard)("(%p,%d)\n",hwnd,id);
1423 SERVER_START_REQ( unregister_hotkey )
1425 req->window = wine_server_user_handle( hwnd );
1426 req->id = id;
1427 if ((ret = !wine_server_call_err( req )))
1429 modifiers = reply->flags;
1430 vk = reply->vkey;
1433 SERVER_END_REQ;
1435 if (ret)
1436 user_driver->pUnregisterHotKey(hwnd, modifiers, vk);
1438 return ret;
1441 /***********************************************************************
1442 * NtUserGetMouseMovePointsEx (win32u.@)
1444 int WINAPI NtUserGetMouseMovePointsEx( UINT size, MOUSEMOVEPOINT *ptin, MOUSEMOVEPOINT *ptout,
1445 int count, DWORD resolution )
1447 cursor_pos_t *pos, positions[64];
1448 int copied;
1449 unsigned int i;
1452 TRACE( "%d, %p, %p, %d, %d\n", size, ptin, ptout, count, (int)resolution );
1454 if ((size != sizeof(MOUSEMOVEPOINT)) || (count < 0) || (count > ARRAY_SIZE( positions )))
1456 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
1457 return -1;
1460 if (!ptin || (!ptout && count))
1462 RtlSetLastWin32Error( ERROR_NOACCESS );
1463 return -1;
1466 if (resolution != GMMP_USE_DISPLAY_POINTS)
1468 FIXME( "only GMMP_USE_DISPLAY_POINTS is supported for now\n" );
1469 RtlSetLastWin32Error( ERROR_POINT_NOT_FOUND );
1470 return -1;
1473 SERVER_START_REQ( get_cursor_history )
1475 wine_server_set_reply( req, &positions, sizeof(positions) );
1476 if (wine_server_call_err( req )) return -1;
1478 SERVER_END_REQ;
1480 for (i = 0; i < ARRAY_SIZE( positions ); i++)
1482 pos = &positions[i];
1483 if (ptin->x == pos->x && ptin->y == pos->y && (!ptin->time || ptin->time == pos->time))
1484 break;
1487 if (i == ARRAY_SIZE( positions ))
1489 RtlSetLastWin32Error( ERROR_POINT_NOT_FOUND );
1490 return -1;
1493 for (copied = 0; copied < count && i < ARRAY_SIZE( positions ); copied++, i++)
1495 pos = &positions[i];
1496 ptout[copied].x = pos->x;
1497 ptout[copied].y = pos->y;
1498 ptout[copied].time = pos->time;
1499 ptout[copied].dwExtraInfo = pos->info;
1502 return copied;
1505 static WORD get_key_state(void)
1507 WORD ret = 0;
1509 if (get_system_metrics( SM_SWAPBUTTON ))
1511 if (NtUserGetAsyncKeyState(VK_RBUTTON) & 0x80) ret |= MK_LBUTTON;
1512 if (NtUserGetAsyncKeyState(VK_LBUTTON) & 0x80) ret |= MK_RBUTTON;
1514 else
1516 if (NtUserGetAsyncKeyState(VK_LBUTTON) & 0x80) ret |= MK_LBUTTON;
1517 if (NtUserGetAsyncKeyState(VK_RBUTTON) & 0x80) ret |= MK_RBUTTON;
1519 if (NtUserGetAsyncKeyState(VK_MBUTTON) & 0x80) ret |= MK_MBUTTON;
1520 if (NtUserGetAsyncKeyState(VK_SHIFT) & 0x80) ret |= MK_SHIFT;
1521 if (NtUserGetAsyncKeyState(VK_CONTROL) & 0x80) ret |= MK_CONTROL;
1522 if (NtUserGetAsyncKeyState(VK_XBUTTON1) & 0x80) ret |= MK_XBUTTON1;
1523 if (NtUserGetAsyncKeyState(VK_XBUTTON2) & 0x80) ret |= MK_XBUTTON2;
1524 return ret;
1527 struct tracking_list
1529 TRACKMOUSEEVENT info;
1530 POINT pos; /* center of hover rectangle */
1533 /* FIXME: move tracking stuff into per-thread data */
1534 static struct tracking_list tracking_info;
1536 static void check_mouse_leave( HWND hwnd, int hittest )
1538 if (tracking_info.info.hwndTrack != hwnd)
1540 if (tracking_info.info.dwFlags & TME_NONCLIENT)
1541 NtUserPostMessage( tracking_info.info.hwndTrack, WM_NCMOUSELEAVE, 0, 0 );
1542 else
1543 NtUserPostMessage( tracking_info.info.hwndTrack, WM_MOUSELEAVE, 0, 0 );
1545 tracking_info.info.dwFlags &= ~TME_LEAVE;
1547 else
1549 if (hittest == HTCLIENT)
1551 if (tracking_info.info.dwFlags & TME_NONCLIENT)
1553 NtUserPostMessage( tracking_info.info.hwndTrack, WM_NCMOUSELEAVE, 0, 0 );
1554 tracking_info.info.dwFlags &= ~TME_LEAVE;
1557 else
1559 if (!(tracking_info.info.dwFlags & TME_NONCLIENT))
1561 NtUserPostMessage( tracking_info.info.hwndTrack, WM_MOUSELEAVE, 0, 0 );
1562 tracking_info.info.dwFlags &= ~TME_LEAVE;
1568 void update_mouse_tracking_info( HWND hwnd )
1570 int hover_width = 0, hover_height = 0, hittest;
1571 POINT pos;
1573 TRACE( "hwnd %p\n", hwnd );
1575 get_cursor_pos( &pos );
1576 hwnd = window_from_point( hwnd, pos, &hittest );
1578 TRACE( "point %s hwnd %p hittest %d\n", wine_dbgstr_point(&pos), hwnd, hittest );
1580 NtUserSystemParametersInfo( SPI_GETMOUSEHOVERWIDTH, 0, &hover_width, 0 );
1581 NtUserSystemParametersInfo( SPI_GETMOUSEHOVERHEIGHT, 0, &hover_height, 0 );
1583 TRACE( "tracked pos %s, current pos %s, hover width %d, hover height %d\n",
1584 wine_dbgstr_point(&tracking_info.pos), wine_dbgstr_point(&pos),
1585 hover_width, hover_height );
1587 if (tracking_info.info.dwFlags & TME_LEAVE)
1588 check_mouse_leave( hwnd, hittest );
1590 if (tracking_info.info.hwndTrack != hwnd)
1591 tracking_info.info.dwFlags &= ~TME_HOVER;
1593 if (tracking_info.info.dwFlags & TME_HOVER)
1595 /* has the cursor moved outside the rectangle centered around pos? */
1596 if ((abs( pos.x - tracking_info.pos.x ) > (hover_width / 2)) ||
1597 (abs( pos.y - tracking_info.pos.y ) > (hover_height / 2)))
1599 tracking_info.pos = pos;
1601 else
1603 if (hittest == HTCLIENT)
1605 screen_to_client(hwnd, &pos);
1606 TRACE( "client cursor pos %s\n", wine_dbgstr_point(&pos) );
1608 NtUserPostMessage( tracking_info.info.hwndTrack, WM_MOUSEHOVER,
1609 get_key_state(), MAKELPARAM( pos.x, pos.y ) );
1611 else
1613 if (tracking_info.info.dwFlags & TME_NONCLIENT)
1614 NtUserPostMessage( tracking_info.info.hwndTrack, WM_NCMOUSEHOVER,
1615 hittest, MAKELPARAM( pos.x, pos.y ) );
1618 /* stop tracking mouse hover */
1619 tracking_info.info.dwFlags &= ~TME_HOVER;
1623 /* stop the timer if the tracking list is empty */
1624 if (!(tracking_info.info.dwFlags & (TME_HOVER | TME_LEAVE)))
1626 kill_system_timer( tracking_info.info.hwndTrack, SYSTEM_TIMER_TRACK_MOUSE );
1627 tracking_info.info.hwndTrack = 0;
1628 tracking_info.info.dwFlags = 0;
1629 tracking_info.info.dwHoverTime = 0;
1633 /***********************************************************************
1634 * NtUserTrackMouseEvent (win32u.@)
1636 BOOL WINAPI NtUserTrackMouseEvent( TRACKMOUSEEVENT *info )
1638 DWORD hover_time;
1639 int hittest;
1640 HWND hwnd;
1641 POINT pos;
1643 TRACE( "size %u, flags %#x, hwnd %p, time %u\n",
1644 (int)info->cbSize, (int)info->dwFlags, info->hwndTrack, (int)info->dwHoverTime );
1646 if (info->cbSize != sizeof(TRACKMOUSEEVENT))
1648 WARN( "wrong size %u\n", (int)info->cbSize );
1649 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
1650 return FALSE;
1653 if (info->dwFlags & TME_QUERY)
1655 *info = tracking_info.info;
1656 info->cbSize = sizeof(TRACKMOUSEEVENT);
1657 return TRUE;
1660 if (!is_window( info->hwndTrack ))
1662 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE );
1663 return FALSE;
1666 hover_time = (info->dwFlags & TME_HOVER) ? info->dwHoverTime : HOVER_DEFAULT;
1668 if (hover_time == HOVER_DEFAULT || hover_time == 0)
1669 NtUserSystemParametersInfo( SPI_GETMOUSEHOVERTIME, 0, &hover_time, 0 );
1671 get_cursor_pos( &pos );
1672 hwnd = window_from_point( info->hwndTrack, pos, &hittest );
1673 TRACE( "point %s hwnd %p hittest %d\n", wine_dbgstr_point(&pos), hwnd, hittest );
1675 if (info->dwFlags & ~(TME_CANCEL | TME_HOVER | TME_LEAVE | TME_NONCLIENT))
1676 FIXME( "ignoring flags %#x\n", (int)info->dwFlags & ~(TME_CANCEL | TME_HOVER | TME_LEAVE | TME_NONCLIENT) );
1678 if (info->dwFlags & TME_CANCEL)
1680 if (tracking_info.info.hwndTrack == info->hwndTrack)
1682 tracking_info.info.dwFlags &= ~(info->dwFlags & ~TME_CANCEL);
1684 /* if we aren't tracking on hover or leave remove this entry */
1685 if (!(tracking_info.info.dwFlags & (TME_HOVER | TME_LEAVE)))
1687 kill_system_timer( tracking_info.info.hwndTrack, SYSTEM_TIMER_TRACK_MOUSE );
1688 tracking_info.info.hwndTrack = 0;
1689 tracking_info.info.dwFlags = 0;
1690 tracking_info.info.dwHoverTime = 0;
1694 else
1696 /* In our implementation, it's possible that another window will receive
1697 * WM_MOUSEMOVE and call TrackMouseEvent before TrackMouseEventProc is
1698 * called. In such a situation, post the WM_MOUSELEAVE now. */
1699 if ((tracking_info.info.dwFlags & TME_LEAVE) && tracking_info.info.hwndTrack != NULL)
1700 check_mouse_leave(hwnd, hittest);
1702 kill_system_timer( tracking_info.info.hwndTrack, SYSTEM_TIMER_TRACK_MOUSE );
1703 tracking_info.info.hwndTrack = 0;
1704 tracking_info.info.dwFlags = 0;
1705 tracking_info.info.dwHoverTime = 0;
1707 if (info->hwndTrack == hwnd)
1709 /* Adding new mouse event to the tracking list */
1710 tracking_info.info = *info;
1711 tracking_info.info.dwHoverTime = hover_time;
1713 /* Initialize HoverInfo variables even if not hover tracking */
1714 tracking_info.pos = pos;
1716 NtUserSetSystemTimer( tracking_info.info.hwndTrack, SYSTEM_TIMER_TRACK_MOUSE, hover_time );
1720 return TRUE;
1723 /**********************************************************************
1724 * set_capture_window
1726 BOOL set_capture_window( HWND hwnd, UINT gui_flags, HWND *prev_ret )
1728 HWND previous = 0;
1729 UINT flags = 0;
1730 BOOL ret;
1732 if (gui_flags & GUI_INMENUMODE) flags |= CAPTURE_MENU;
1733 if (gui_flags & GUI_INMOVESIZE) flags |= CAPTURE_MOVESIZE;
1735 SERVER_START_REQ( set_capture_window )
1737 req->handle = wine_server_user_handle( hwnd );
1738 req->flags = flags;
1739 if ((ret = !wine_server_call_err( req )))
1741 previous = wine_server_ptr_handle( reply->previous );
1742 hwnd = wine_server_ptr_handle( reply->full_handle );
1745 SERVER_END_REQ;
1747 if (ret)
1749 user_driver->pSetCapture( hwnd, gui_flags );
1751 if (previous)
1752 send_message( previous, WM_CAPTURECHANGED, 0, (LPARAM)hwnd );
1754 if (prev_ret) *prev_ret = previous;
1756 return ret;
1759 /**********************************************************************
1760 * NtUserSetCapture (win32u.@)
1762 HWND WINAPI NtUserSetCapture( HWND hwnd )
1764 HWND previous = 0;
1766 set_capture_window( hwnd, 0, &previous );
1767 return previous;
1770 /**********************************************************************
1771 * release_capture
1773 BOOL release_capture(void)
1775 BOOL ret = set_capture_window( 0, 0, NULL );
1777 /* Somebody may have missed some mouse movements */
1778 if (ret)
1780 INPUT input = { .type = INPUT_MOUSE };
1781 input.mi.dwFlags = MOUSEEVENTF_MOVE;
1782 NtUserSendInput( 1, &input, sizeof(input) );
1785 return ret;
1788 /*****************************************************************
1789 * set_focus_window
1791 * Change the focus window, sending the WM_SETFOCUS and WM_KILLFOCUS messages
1793 static HWND set_focus_window( HWND hwnd )
1795 HWND previous = 0, ime_hwnd;
1796 BOOL ret;
1798 SERVER_START_REQ( set_focus_window )
1800 req->handle = wine_server_user_handle( hwnd );
1801 if ((ret = !wine_server_call_err( req )))
1802 previous = wine_server_ptr_handle( reply->previous );
1804 SERVER_END_REQ;
1805 if (!ret) return 0;
1806 if (previous == hwnd) return previous;
1808 if (previous)
1810 send_message( previous, WM_KILLFOCUS, (WPARAM)hwnd, 0 );
1812 ime_hwnd = get_default_ime_window( previous );
1813 if (ime_hwnd)
1814 send_message( ime_hwnd, WM_IME_INTERNAL, IME_INTERNAL_DEACTIVATE,
1815 HandleToUlong(previous) );
1817 if (hwnd != get_focus()) return previous; /* changed by the message */
1819 if (is_window(hwnd))
1821 user_driver->pSetFocus(hwnd);
1823 ime_hwnd = get_default_ime_window( hwnd );
1824 if (ime_hwnd)
1825 send_message( ime_hwnd, WM_IME_INTERNAL, IME_INTERNAL_ACTIVATE,
1826 HandleToUlong(hwnd) );
1828 if (previous)
1829 NtUserNotifyWinEvent( EVENT_OBJECT_FOCUS, hwnd, OBJID_CLIENT, 0 );
1831 send_message( hwnd, WM_SETFOCUS, (WPARAM)previous, 0 );
1833 return previous;
1836 /*******************************************************************
1837 * set_active_window
1839 static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus )
1841 HWND previous = get_active_window();
1842 BOOL ret;
1843 DWORD old_thread, new_thread;
1844 CBTACTIVATESTRUCT cbt;
1846 if (previous == hwnd)
1848 if (prev) *prev = hwnd;
1849 goto done;
1852 /* call CBT hook chain */
1853 cbt.fMouse = mouse;
1854 cbt.hWndActive = previous;
1855 if (call_hooks( WH_CBT, HCBT_ACTIVATE, (WPARAM)hwnd, (LPARAM)&cbt, sizeof(cbt) )) return FALSE;
1857 if (is_window( previous ))
1859 send_message( previous, WM_NCACTIVATE, FALSE, (LPARAM)hwnd );
1860 send_message( previous, WM_ACTIVATE,
1861 MAKEWPARAM( WA_INACTIVE, is_iconic(previous) ), (LPARAM)hwnd );
1864 SERVER_START_REQ( set_active_window )
1866 req->handle = wine_server_user_handle( hwnd );
1867 if ((ret = !wine_server_call_err( req )))
1868 previous = wine_server_ptr_handle( reply->previous );
1870 SERVER_END_REQ;
1871 if (!ret) return FALSE;
1872 if (prev) *prev = previous;
1873 if (previous == hwnd) goto done;
1875 if (hwnd)
1877 /* send palette messages */
1878 if (send_message( hwnd, WM_QUERYNEWPALETTE, 0, 0 ))
1879 send_message_timeout( HWND_BROADCAST, WM_PALETTEISCHANGING, (WPARAM)hwnd, 0,
1880 SMTO_ABORTIFHUNG, 2000, FALSE );
1881 if (!is_window(hwnd)) return FALSE;
1884 old_thread = previous ? get_window_thread( previous, NULL ) : 0;
1885 new_thread = hwnd ? get_window_thread( hwnd, NULL ) : 0;
1887 if (old_thread != new_thread)
1889 HWND *list, *phwnd;
1891 if ((list = list_window_children( NULL, get_desktop_window(), NULL, 0 )))
1893 if (old_thread)
1895 for (phwnd = list; *phwnd; phwnd++)
1897 if (get_window_thread( *phwnd, NULL ) == old_thread)
1898 send_message( *phwnd, WM_ACTIVATEAPP, 0, new_thread );
1901 if (new_thread)
1903 for (phwnd = list; *phwnd; phwnd++)
1905 if (get_window_thread( *phwnd, NULL ) == new_thread)
1906 send_message( *phwnd, WM_ACTIVATEAPP, 1, old_thread );
1909 free( list );
1913 if (is_window(hwnd))
1915 send_message( hwnd, WM_NCACTIVATE, hwnd == NtUserGetForegroundWindow(), (LPARAM)previous );
1916 send_message( hwnd, WM_ACTIVATE,
1917 MAKEWPARAM( mouse ? WA_CLICKACTIVE : WA_ACTIVE, is_iconic(hwnd) ),
1918 (LPARAM)previous );
1919 if (NtUserGetAncestor( hwnd, GA_PARENT ) == get_desktop_window())
1920 NtUserPostMessage( get_desktop_window(), WM_PARENTNOTIFY, WM_NCACTIVATE, (LPARAM)hwnd );
1923 /* now change focus if necessary */
1924 if (focus)
1926 GUITHREADINFO info;
1928 info.cbSize = sizeof(info);
1929 NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info );
1930 /* Do not change focus if the window is no more active */
1931 if (hwnd == info.hwndActive)
1933 if (!info.hwndFocus || !hwnd || NtUserGetAncestor( info.hwndFocus, GA_ROOT ) != hwnd)
1934 set_focus_window( hwnd );
1938 done:
1939 if (hwnd) clip_fullscreen_window( hwnd, FALSE );
1940 return TRUE;
1943 /**********************************************************************
1944 * NtUserSetActiveWindow (win32u.@)
1946 HWND WINAPI NtUserSetActiveWindow( HWND hwnd )
1948 HWND prev;
1950 TRACE( "%p\n", hwnd );
1952 if (hwnd)
1954 LONG style;
1956 hwnd = get_full_window_handle( hwnd );
1957 if (!is_window( hwnd ))
1959 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE );
1960 return 0;
1963 style = get_window_long( hwnd, GWL_STYLE );
1964 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD)
1965 return get_active_window(); /* Windows doesn't seem to return an error here */
1968 if (!set_active_window( hwnd, &prev, FALSE, TRUE )) return 0;
1969 return prev;
1972 /*****************************************************************
1973 * NtUserSetFocus (win32u.@)
1975 HWND WINAPI NtUserSetFocus( HWND hwnd )
1977 HWND hwndTop = hwnd;
1978 HWND previous = get_focus();
1980 TRACE( "%p prev %p\n", hwnd, previous );
1982 if (hwnd)
1984 /* Check if we can set the focus to this window */
1985 hwnd = get_full_window_handle( hwnd );
1986 if (!is_window( hwnd ))
1988 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE );
1989 return 0;
1991 if (hwnd == previous) return previous; /* nothing to do */
1992 for (;;)
1994 HWND parent;
1995 LONG style = get_window_long( hwndTop, GWL_STYLE );
1996 if (style & (WS_MINIMIZE | WS_DISABLED)) return 0;
1997 if (!(style & WS_CHILD)) break;
1998 parent = NtUserGetAncestor( hwndTop, GA_PARENT );
1999 if (!parent || parent == get_desktop_window())
2001 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return 0;
2002 break;
2004 if (parent == get_hwnd_message_parent()) return 0;
2005 hwndTop = parent;
2008 /* call hooks */
2009 if (call_hooks( WH_CBT, HCBT_SETFOCUS, (WPARAM)hwnd, (LPARAM)previous, 0 )) return 0;
2011 /* activate hwndTop if needed. */
2012 if (hwndTop != get_active_window())
2014 if (!set_active_window( hwndTop, NULL, FALSE, FALSE )) return 0;
2015 if (!is_window( hwnd )) return 0; /* Abort if window destroyed */
2017 /* Do not change focus if the window is no longer active */
2018 if (hwndTop != get_active_window()) return 0;
2021 else /* NULL hwnd passed in */
2023 if (!previous) return 0; /* nothing to do */
2024 if (call_hooks( WH_CBT, HCBT_SETFOCUS, 0, (LPARAM)previous, 0 )) return 0;
2027 /* change focus and send messages */
2028 return set_focus_window( hwnd );
2031 /*******************************************************************
2032 * set_foreground_window
2034 BOOL set_foreground_window( HWND hwnd, BOOL mouse )
2036 BOOL ret, send_msg_old = FALSE, send_msg_new = FALSE;
2037 HWND previous = 0;
2039 if (mouse) hwnd = get_full_window_handle( hwnd );
2041 SERVER_START_REQ( set_foreground_window )
2043 req->handle = wine_server_user_handle( hwnd );
2044 if ((ret = !wine_server_call_err( req )))
2046 previous = wine_server_ptr_handle( reply->previous );
2047 send_msg_old = reply->send_msg_old;
2048 send_msg_new = reply->send_msg_new;
2051 SERVER_END_REQ;
2053 if (ret && previous != hwnd)
2055 if (send_msg_old) /* old window belongs to other thread */
2056 NtUserMessageCall( previous, WM_WINE_SETACTIVEWINDOW, 0, 0,
2057 0, NtUserSendNotifyMessage, FALSE );
2058 else if (send_msg_new) /* old window belongs to us but new one to other thread */
2059 ret = set_active_window( 0, NULL, mouse, TRUE );
2061 if (send_msg_new) /* new window belongs to other thread */
2062 NtUserMessageCall( hwnd, WM_WINE_SETACTIVEWINDOW, (WPARAM)hwnd, 0,
2063 0, NtUserSendNotifyMessage, FALSE );
2064 else /* new window belongs to us */
2065 ret = set_active_window( hwnd, NULL, mouse, TRUE );
2067 return ret;
2070 static struct
2072 HBITMAP bitmap;
2073 unsigned int timeout;
2074 } caret = {0, 500};
2076 static void display_caret( HWND hwnd, const RECT *r )
2078 HDC dc, mem_dc;
2080 /* do not use DCX_CACHE here, since coördinates are in logical units */
2081 if (!(dc = NtUserGetDCEx( hwnd, 0, DCX_USESTYLE )))
2082 return;
2083 mem_dc = NtGdiCreateCompatibleDC(dc);
2084 if (mem_dc)
2086 HBITMAP prev_bitmap;
2088 prev_bitmap = NtGdiSelectBitmap( mem_dc, caret.bitmap );
2089 NtGdiBitBlt( dc, r->left, r->top, r->right-r->left, r->bottom-r->top, mem_dc, 0, 0, SRCINVERT, 0, 0 );
2090 NtGdiSelectBitmap( mem_dc, prev_bitmap );
2091 NtGdiDeleteObjectApp( mem_dc );
2093 NtUserReleaseDC( hwnd, dc );
2096 static unsigned int get_caret_registry_timeout(void)
2098 char value_buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[11 * sizeof(WCHAR)])];
2099 KEY_VALUE_PARTIAL_INFORMATION *value = (void *)value_buffer;
2100 unsigned int ret = 500;
2101 HKEY key;
2103 if (!(key = reg_open_hkcu_key( "Control Panel\\Desktop" )))
2104 return ret;
2106 if (query_reg_ascii_value( key, "CursorBlinkRate", value, sizeof(value_buffer) ))
2107 ret = wcstoul( (WCHAR *)value->Data, NULL, 10 );
2108 NtClose( key );
2109 return ret;
2112 /*****************************************************************
2113 * NtUserCreateCaret (win32u.@)
2115 BOOL WINAPI NtUserCreateCaret( HWND hwnd, HBITMAP bitmap, int width, int height )
2117 HBITMAP caret_bitmap = 0;
2118 int old_state = 0;
2119 int hidden = 0;
2120 HWND prev = 0;
2121 BOOL ret;
2122 RECT r;
2124 TRACE( "hwnd %p, bitmap %p, width %d, height %d\n", hwnd, bitmap, width, height );
2126 if (!hwnd) return FALSE;
2128 if (bitmap && bitmap != (HBITMAP)1)
2130 BITMAP bitmap_data;
2132 if (!NtGdiExtGetObjectW( bitmap, sizeof(bitmap_data), &bitmap_data )) return FALSE;
2133 width = bitmap_data.bmWidth;
2134 height = bitmap_data.bmHeight;
2135 caret_bitmap = NtGdiCreateBitmap( bitmap_data.bmWidth, bitmap_data.bmHeight,
2136 bitmap_data.bmPlanes, bitmap_data.bmBitsPixel, NULL );
2137 if (caret_bitmap)
2139 size_t size = bitmap_data.bmWidthBytes * bitmap_data.bmHeight;
2140 BYTE *bits = malloc( size );
2142 NtGdiGetBitmapBits( bitmap, size, bits );
2143 NtGdiSetBitmapBits( caret_bitmap, size, bits );
2144 free( bits );
2147 else
2149 HDC dc;
2151 if (!width) width = get_system_metrics( SM_CXBORDER );
2152 if (!height) height = get_system_metrics( SM_CYBORDER );
2154 /* create the uniform bitmap on the fly */
2155 dc = NtUserGetDCEx( hwnd, 0, DCX_USESTYLE );
2156 if (dc)
2158 HDC mem_dc = NtGdiCreateCompatibleDC( dc );
2159 if (mem_dc)
2161 if ((caret_bitmap = NtGdiCreateCompatibleBitmap( mem_dc, width, height )))
2163 HBITMAP prev_bitmap = NtGdiSelectBitmap( mem_dc, caret_bitmap );
2164 SetRect( &r, 0, 0, width, height );
2165 fill_rect( mem_dc, &r, GetStockObject( bitmap ? GRAY_BRUSH : WHITE_BRUSH ));
2166 NtGdiSelectBitmap( mem_dc, prev_bitmap );
2168 NtGdiDeleteObjectApp( mem_dc );
2170 NtUserReleaseDC( hwnd, dc );
2173 if (!caret_bitmap) return FALSE;
2175 SERVER_START_REQ( set_caret_window )
2177 req->handle = wine_server_user_handle( hwnd );
2178 req->width = width;
2179 req->height = height;
2180 if ((ret = !wine_server_call_err( req )))
2182 prev = wine_server_ptr_handle( reply->previous );
2183 r.left = reply->old_rect.left;
2184 r.top = reply->old_rect.top;
2185 r.right = reply->old_rect.right;
2186 r.bottom = reply->old_rect.bottom;
2187 old_state = reply->old_state;
2188 hidden = reply->old_hide;
2191 SERVER_END_REQ;
2192 if (!ret) return FALSE;
2194 if (prev && !hidden) /* hide the previous one */
2196 /* FIXME: won't work if prev belongs to a different process */
2197 kill_system_timer( prev, SYSTEM_TIMER_CARET );
2198 if (old_state) display_caret( prev, &r );
2201 if (caret.bitmap) NtGdiDeleteObjectApp( caret.bitmap );
2202 caret.bitmap = caret_bitmap;
2203 caret.timeout = get_caret_registry_timeout();
2204 return TRUE;
2207 /*******************************************************************
2208 * destroy_caret
2210 BOOL destroy_caret(void)
2212 int old_state = 0;
2213 int hidden = 0;
2214 HWND prev = 0;
2215 BOOL ret;
2216 RECT r;
2218 SERVER_START_REQ( set_caret_window )
2220 req->handle = 0;
2221 req->width = 0;
2222 req->height = 0;
2223 if ((ret = !wine_server_call_err( req )))
2225 prev = wine_server_ptr_handle( reply->previous );
2226 r.left = reply->old_rect.left;
2227 r.top = reply->old_rect.top;
2228 r.right = reply->old_rect.right;
2229 r.bottom = reply->old_rect.bottom;
2230 old_state = reply->old_state;
2231 hidden = reply->old_hide;
2234 SERVER_END_REQ;
2236 if (ret && prev && !hidden)
2238 /* FIXME: won't work if prev belongs to a different process */
2239 kill_system_timer( prev, SYSTEM_TIMER_CARET );
2240 if (old_state) display_caret( prev, &r );
2242 if (caret.bitmap) NtGdiDeleteObjectApp( caret.bitmap );
2243 caret.bitmap = 0;
2244 return ret;
2247 /*****************************************************************
2248 * NtUserGetCaretBlinkTime (win32u.@)
2250 UINT WINAPI NtUserGetCaretBlinkTime(void)
2252 return caret.timeout;
2255 /*******************************************************************
2256 * set_caret_blink_time
2258 BOOL set_caret_blink_time( unsigned int time )
2260 TRACE( "time %u\n", time );
2262 caret.timeout = time;
2263 /* FIXME: update the timer */
2264 return TRUE;
2267 /*****************************************************************
2268 * NtUserGetCaretPos (win32u.@)
2270 BOOL WINAPI NtUserGetCaretPos( POINT *pt )
2272 BOOL ret;
2274 SERVER_START_REQ( set_caret_info )
2276 req->flags = 0; /* don't set anything */
2277 req->handle = 0;
2278 req->x = 0;
2279 req->y = 0;
2280 req->hide = 0;
2281 req->state = 0;
2282 if ((ret = !wine_server_call_err( req )))
2284 pt->x = reply->old_rect.left;
2285 pt->y = reply->old_rect.top;
2288 SERVER_END_REQ;
2289 return ret;
2292 /*******************************************************************
2293 * set_caret_pos
2295 BOOL set_caret_pos( int x, int y )
2297 int old_state = 0;
2298 int hidden = 0;
2299 HWND hwnd = 0;
2300 BOOL ret;
2301 RECT r;
2303 TRACE( "(%d, %d)\n", x, y );
2305 SERVER_START_REQ( set_caret_info )
2307 req->flags = SET_CARET_POS|SET_CARET_STATE;
2308 req->handle = 0;
2309 req->x = x;
2310 req->y = y;
2311 req->hide = 0;
2312 req->state = CARET_STATE_ON_IF_MOVED;
2313 if ((ret = !wine_server_call_err( req )))
2315 hwnd = wine_server_ptr_handle( reply->full_handle );
2316 r.left = reply->old_rect.left;
2317 r.top = reply->old_rect.top;
2318 r.right = reply->old_rect.right;
2319 r.bottom = reply->old_rect.bottom;
2320 old_state = reply->old_state;
2321 hidden = reply->old_hide;
2324 SERVER_END_REQ;
2325 if (ret && !hidden && (x != r.left || y != r.top))
2327 if (old_state) display_caret( hwnd, &r );
2328 r.right += x - r.left;
2329 r.bottom += y - r.top;
2330 r.left = x;
2331 r.top = y;
2332 display_caret( hwnd, &r );
2333 NtUserSetSystemTimer( hwnd, SYSTEM_TIMER_CARET, caret.timeout );
2335 return ret;
2338 /*****************************************************************
2339 * NtUserShowCaret (win32u.@)
2341 BOOL WINAPI NtUserShowCaret( HWND hwnd )
2343 int hidden = 0;
2344 BOOL ret;
2345 RECT r;
2347 SERVER_START_REQ( set_caret_info )
2349 req->flags = SET_CARET_HIDE | SET_CARET_STATE;
2350 req->handle = wine_server_user_handle( hwnd );
2351 req->x = 0;
2352 req->y = 0;
2353 req->hide = -1;
2354 req->state = CARET_STATE_ON;
2355 if ((ret = !wine_server_call_err( req )))
2357 hwnd = wine_server_ptr_handle( reply->full_handle );
2358 r.left = reply->old_rect.left;
2359 r.top = reply->old_rect.top;
2360 r.right = reply->old_rect.right;
2361 r.bottom = reply->old_rect.bottom;
2362 hidden = reply->old_hide;
2365 SERVER_END_REQ;
2367 if (ret && hidden == 1) /* hidden was 1 so it's now 0 */
2369 display_caret( hwnd, &r );
2370 NtUserSetSystemTimer( hwnd, SYSTEM_TIMER_CARET, caret.timeout );
2372 return ret;
2375 /*****************************************************************
2376 * NtUserHideCaret (win32u.@)
2378 BOOL WINAPI NtUserHideCaret( HWND hwnd )
2380 int old_state = 0;
2381 int hidden = 0;
2382 BOOL ret;
2383 RECT r;
2385 SERVER_START_REQ( set_caret_info )
2387 req->flags = SET_CARET_HIDE | SET_CARET_STATE;
2388 req->handle = wine_server_user_handle( hwnd );
2389 req->x = 0;
2390 req->y = 0;
2391 req->hide = 1;
2392 req->state = CARET_STATE_OFF;
2393 if ((ret = !wine_server_call_err( req )))
2395 hwnd = wine_server_ptr_handle( reply->full_handle );
2396 r.left = reply->old_rect.left;
2397 r.top = reply->old_rect.top;
2398 r.right = reply->old_rect.right;
2399 r.bottom = reply->old_rect.bottom;
2400 old_state = reply->old_state;
2401 hidden = reply->old_hide;
2404 SERVER_END_REQ;
2406 if (ret && !hidden)
2408 if (old_state) display_caret( hwnd, &r );
2409 kill_system_timer( hwnd, SYSTEM_TIMER_CARET );
2411 return ret;
2414 void toggle_caret( HWND hwnd )
2416 BOOL ret;
2417 RECT r;
2418 int hidden = 0;
2420 SERVER_START_REQ( set_caret_info )
2422 req->flags = SET_CARET_STATE;
2423 req->handle = wine_server_user_handle( hwnd );
2424 req->x = 0;
2425 req->y = 0;
2426 req->hide = 0;
2427 req->state = CARET_STATE_TOGGLE;
2428 if ((ret = !wine_server_call( req )))
2430 hwnd = wine_server_ptr_handle( reply->full_handle );
2431 r.left = reply->old_rect.left;
2432 r.top = reply->old_rect.top;
2433 r.right = reply->old_rect.right;
2434 r.bottom = reply->old_rect.bottom;
2435 hidden = reply->old_hide;
2438 SERVER_END_REQ;
2440 if (ret && !hidden) display_caret( hwnd, &r );
2444 /**********************************************************************
2445 * NtUserEnableMouseInPointer (win32u.@)
2447 BOOL WINAPI NtUserEnableMouseInPointer( BOOL enable )
2449 FIXME( "enable %u stub!\n", enable );
2450 RtlSetLastWin32Error( ERROR_CALL_NOT_IMPLEMENTED );
2451 return FALSE;
2454 /**********************************************************************
2455 * NtUserIsMouseInPointerEnabled (win32u.@)
2457 BOOL WINAPI NtUserIsMouseInPointerEnabled(void)
2459 FIXME( "stub!\n" );
2460 RtlSetLastWin32Error( ERROR_CALL_NOT_IMPLEMENTED );
2461 return FALSE;
2464 static BOOL is_captured_by_system(void)
2466 GUITHREADINFO info;
2467 info.cbSize = sizeof(info);
2468 return NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info ) && info.hwndCapture && (info.flags & (GUI_INMOVESIZE | GUI_INMENUMODE));
2471 /***********************************************************************
2472 * clip_fullscreen_window
2474 * Turn on clipping if the active window is fullscreen.
2476 BOOL clip_fullscreen_window( HWND hwnd, BOOL reset )
2478 struct user_thread_info *thread_info = get_user_thread_info();
2479 MONITORINFO monitor_info = {.cbSize = sizeof(MONITORINFO)};
2480 RECT rect;
2481 HMONITOR monitor;
2482 DWORD style;
2483 BOOL ret;
2485 if (hwnd == NtUserGetDesktopWindow()) return FALSE;
2486 if (hwnd != NtUserGetForegroundWindow()) return FALSE;
2488 style = NtUserGetWindowLongW( hwnd, GWL_STYLE );
2489 if (!(style & WS_VISIBLE)) return FALSE;
2490 if ((style & (WS_POPUP | WS_CHILD)) == WS_CHILD) return FALSE;
2491 /* maximized windows don't count as full screen */
2492 if ((style & WS_MAXIMIZE) && (style & WS_CAPTION) == WS_CAPTION) return FALSE;
2494 if (!NtUserGetWindowRect( hwnd, &rect )) return FALSE;
2495 if (!NtUserIsWindowRectFullScreen( &rect )) return FALSE;
2496 if (is_captured_by_system()) return FALSE;
2497 if (NtGetTickCount() - thread_info->clipping_reset < 1000) return FALSE;
2498 if (!reset && clipping_cursor && thread_info->clipping_cursor) return FALSE; /* already clipping */
2500 if (!(monitor = NtUserMonitorFromWindow( hwnd, MONITOR_DEFAULTTONEAREST ))) return FALSE;
2501 if (!NtUserGetMonitorInfo( monitor, &monitor_info )) return FALSE;
2502 if (!grab_fullscreen)
2504 RECT virtual_rect = NtUserGetVirtualScreenRect();
2505 if (!EqualRect( &monitor_info.rcMonitor, &virtual_rect )) return FALSE;
2506 if (is_virtual_desktop()) return FALSE;
2509 TRACE( "win %p clipping fullscreen\n", hwnd );
2511 SERVER_START_REQ( set_cursor )
2513 req->flags = SET_CURSOR_CLIP | SET_CURSOR_FSCLIP;
2514 req->clip.left = monitor_info.rcMonitor.left;
2515 req->clip.top = monitor_info.rcMonitor.top;
2516 req->clip.right = monitor_info.rcMonitor.right;
2517 req->clip.bottom = monitor_info.rcMonitor.bottom;
2518 ret = !wine_server_call( req );
2520 SERVER_END_REQ;
2522 return ret;
2525 /**********************************************************************
2526 * NtUserGetPointerInfoList (win32u.@)
2528 BOOL WINAPI NtUserGetPointerInfoList( UINT32 id, POINTER_INPUT_TYPE type, UINT_PTR unk0, UINT_PTR unk1, SIZE_T size,
2529 UINT32 *entry_count, UINT32 *pointer_count, void *pointer_info )
2531 FIXME( "id %#x, type %#x, unk0 %#zx, unk1 %#zx, size %#zx, entry_count %p, pointer_count %p, pointer_info %p stub!\n",
2532 id, (int)type, (size_t)unk0, (size_t)unk1, (size_t)size, entry_count, pointer_count, pointer_info );
2533 RtlSetLastWin32Error( ERROR_CALL_NOT_IMPLEMENTED );
2534 return FALSE;
2537 BOOL get_clip_cursor( RECT *rect )
2539 UINT dpi;
2540 BOOL ret;
2542 if (!rect) return FALSE;
2544 SERVER_START_REQ( set_cursor )
2546 req->flags = 0;
2547 if ((ret = !wine_server_call( req )))
2549 rect->left = reply->new_clip.left;
2550 rect->top = reply->new_clip.top;
2551 rect->right = reply->new_clip.right;
2552 rect->bottom = reply->new_clip.bottom;
2555 SERVER_END_REQ;
2557 if (ret && (dpi = get_thread_dpi()))
2559 HMONITOR monitor = monitor_from_rect( rect, MONITOR_DEFAULTTOPRIMARY, 0 );
2560 *rect = map_dpi_rect( *rect, get_monitor_dpi( monitor ), dpi );
2562 return ret;
2565 BOOL process_wine_clipcursor( HWND hwnd, UINT flags, BOOL reset )
2567 struct user_thread_info *thread_info = get_user_thread_info();
2568 RECT rect, virtual_rect = NtUserGetVirtualScreenRect();
2569 BOOL was_clipping, empty = !!(flags & SET_CURSOR_NOCLIP);
2571 TRACE( "hwnd %p, flags %#x, reset %u\n", hwnd, flags, reset );
2573 if ((was_clipping = thread_info->clipping_cursor)) InterlockedDecrement( &clipping_cursor );
2574 thread_info->clipping_cursor = FALSE;
2576 if (reset)
2578 thread_info->clipping_reset = NtGetTickCount();
2579 return user_driver->pClipCursor( NULL, TRUE );
2582 if (!grab_pointer) return TRUE;
2584 /* we are clipping if the clip rectangle is smaller than the screen */
2585 get_clip_cursor( &rect );
2586 intersect_rect( &rect, &rect, &virtual_rect );
2587 if (EqualRect( &rect, &virtual_rect )) empty = TRUE;
2588 if (empty && !(flags & SET_CURSOR_FSCLIP))
2590 /* if currently clipping, check if we should switch to fullscreen clipping */
2591 if (was_clipping && clip_fullscreen_window( hwnd, TRUE )) return TRUE;
2592 return user_driver->pClipCursor( NULL, FALSE );
2595 if (!user_driver->pClipCursor( &rect, FALSE )) return FALSE;
2596 InterlockedIncrement( &clipping_cursor );
2597 thread_info->clipping_cursor = TRUE;
2598 return TRUE;
2601 /***********************************************************************
2602 * NtUserClipCursor (win32u.@)
2604 BOOL WINAPI NtUserClipCursor( const RECT *rect )
2606 UINT dpi;
2607 BOOL ret;
2608 RECT new_rect;
2610 TRACE( "Clipping to %s\n", wine_dbgstr_rect(rect) );
2612 if (rect)
2614 if (rect->left > rect->right || rect->top > rect->bottom) return FALSE;
2615 if ((dpi = get_thread_dpi()))
2617 HMONITOR monitor = monitor_from_rect( rect, MONITOR_DEFAULTTOPRIMARY, dpi );
2618 new_rect = map_dpi_rect( *rect, dpi, get_monitor_dpi( monitor ));
2619 rect = &new_rect;
2623 SERVER_START_REQ( set_cursor )
2625 if (rect)
2627 req->flags = SET_CURSOR_CLIP;
2628 req->clip.left = rect->left;
2629 req->clip.top = rect->top;
2630 req->clip.right = rect->right;
2631 req->clip.bottom = rect->bottom;
2633 else req->flags = SET_CURSOR_NOCLIP;
2635 ret = !wine_server_call( req );
2637 SERVER_END_REQ;
2639 return ret;