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
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"
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
},
135 static const MODIFIERS modifiers
=
137 .pVkToBit
= (VK_TO_BIT
*)vk_to_bit
,
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
= {'-', '-'}},
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'}},
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'}},
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'}},
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])},
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
},
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
},
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
},
388 static const VSC_VK vsc_to_vk_e1
[] =
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] )
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
;
461 for (bits
= 0; bits
<= mods
->wMaxModBits
; ++bits
)
462 if (mods
->ModNumber
[bits
] == mod
) return bits
;
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
;
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
;
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;
540 /*******************************************************************
541 * NtUserGetForegroundWindow (win32u.@)
543 HWND WINAPI
NtUserGetForegroundWindow(void)
547 SERVER_START_REQ( get_thread_input
)
550 if (!wine_server_call_err( req
)) ret
= wine_server_ptr_handle( reply
->foreground
);
556 /* see GetActiveWindow */
557 HWND
get_active_window(void)
560 info
.cbSize
= sizeof(info
);
561 return NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info
) ? info
.hwndActive
: 0;
565 HWND
get_capture(void)
568 info
.cbSize
= sizeof(info
);
569 return NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info
) ? info
.hwndCapture
: 0;
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
)
587 SERVER_START_REQ( attach_thread_input
)
589 req
->tid_from
= from
;
591 req
->attach
= attach
;
592 ret
= !wine_server_call_err( req
);
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
)
621 if (input
->mi
.dwFlags
& MOUSEEVENTF_VIRTUALDESK
)
622 rc
= get_virtual_screen_rect( 0 );
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);
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])
641 if (abs( input
->mi
.dx
) > accel
[1] && accel
[2] == 2) input
->mi
.dx
*= 2;
643 if (abs(input
->mi
.dy
) > accel
[0])
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
)
657 NTSTATUS status
= STATUS_SUCCESS
;
659 if (size
!= sizeof(INPUT
))
661 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
667 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
673 RtlSetLastWin32Error( ERROR_NOACCESS
);
677 for (i
= 0; i
< count
; i
++)
679 INPUT input
= inputs
[i
];
683 /* we need to update the coordinates to what the server expects */
684 update_mouse_coords( &input
);
687 status
= send_hardware_message( 0, &input
, NULL
, SEND_HWMSG_INJECTED
);
690 RtlSetLastWin32Error( ERROR_CALL_NOT_IMPLEMENTED
);
696 RtlSetLastWin32Error( RtlNtStatusToDosError(status
) );
704 /***********************************************************************
705 * NtUserSetCursorPos (win32u.@)
707 BOOL WINAPI
NtUserSetCursorPos( INT x
, INT y
)
711 INT prev_x
, prev_y
, new_x
, new_y
;
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
;
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
;
734 if (ret
&& (prev_x
!= new_x
|| prev_y
!= new_y
)) user_driver
->pSetCursorPos( new_x
, new_y
);
738 /***********************************************************************
741 BOOL
get_cursor_pos( POINT
*pt
)
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
;
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
);
770 /***********************************************************************
771 * NtUserGetCursorInfo (win32u.@)
773 BOOL WINAPI
NtUserGetCursorInfo( CURSORINFO
*info
)
777 if (!info
) return FALSE
;
779 SERVER_START_REQ( get_thread_input
)
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;
789 get_cursor_pos( &info
->ptScreenPos
);
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
;
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 */
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
;
826 SERVER_START_REQ( get_key_state
)
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;
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
;
857 /***********************************************************************
858 * NtUserGetQueueStatus (win32u.@)
860 DWORD WINAPI
NtUserGetQueueStatus( UINT flags
)
864 if (flags
& ~(QS_ALLINPUT
| QS_ALLPOSTMESSAGE
| QS_SMRESULT
))
866 RtlSetLastWin32Error( ERROR_INVALID_FLAGS
);
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
);
882 /***********************************************************************
885 DWORD
get_input_state(void)
889 check_for_events( QS_INPUT
);
891 SERVER_START_REQ( get_queue_status
)
894 wine_server_call( req
);
895 ret
= reply
->wake_bits
& (QS_KEY
| QS_MOUSEBUTTON
);
901 /***********************************************************************
902 * get_locale_kbd_layout
904 static HKL
get_locale_kbd_layout(void)
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 */
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();
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
)
966 SERVER_START_REQ( get_key_state
)
969 if (!wine_server_call( req
)) retval
= (signed char)(reply
->state
& 0x81);
972 TRACE("key (0x%x) -> %x\n", vkey
, retval
);
976 /**********************************************************************
977 * NtUserGetKeyboardState (win32u.@)
979 BOOL WINAPI
NtUserGetKeyboardState( BYTE
*state
)
984 TRACE("(%p)\n", state
);
986 memset( state
, 0, 256 );
987 SERVER_START_REQ( get_key_state
)
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;
998 /**********************************************************************
999 * NtUserSetKeyboardState (win32u.@)
1001 BOOL WINAPI
NtUserSetKeyboardState( BYTE
*state
)
1005 SERVER_START_REQ( set_key_state
)
1007 wine_server_add_data( req
, state
, 256 );
1008 ret
= !wine_server_call_err( req
);
1014 /******************************************************************************
1015 * NtUserVkKeyScanEx (win32u.@)
1017 WORD WINAPI
NtUserVkKeyScanEx( WCHAR chr
, HKL layout
)
1019 const KBDTABLES
*kbd_tables
= &kbdus_tables
;
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
);
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];
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
;
1047 case MAPVK_VK_TO_VSC_EX
:
1048 case MAPVK_VK_TO_VSC
:
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;
1076 else if (ret
>= 0x100) ret
+= 0xdf00;
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
)
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;
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
];
1103 FIXME_(keyboard
)( "unknown type %d\n", type
);
1107 TRACE_(keyboard
)( "returning 0x%04x\n", 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)
1128 kbd_tables_init_vsc2vk( kbd_tables
, vsc2vk
);
1129 switch ((vkey
= vsc2vk
[code
]))
1134 for (code
= 0; code
< ARRAY_SIZE(vsc2vk
); ++code
)
1135 if (vsc2vk
[code
] == (vkey
- 1)) 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
) );
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
);
1158 TRACE_(keyboard
)( "ret %d, str %s.\n", len
, debugstr_w(buffer
) );
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};
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)
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
) );
1191 /**********************************************************************
1192 * NtUserActivateKeyboardLayout (win32u.@)
1194 HKL WINAPI
NtUserActivateKeyboardLayout( HKL layout
, UINT flags
)
1196 struct user_thread_info
*info
= get_user_thread_info();
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" );
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" );
1220 if (!user_driver
->pActivateKeyboardLayout( layout
, flags
))
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
) );
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();
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
)
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;
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();
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);
1296 tmp
= MAKELONG( LOWORD( layout
), LOWORD( tmp
) );
1297 if (layout
== UlongToHandle( tmp
)) continue;
1300 if (size
&& layouts
)
1302 layouts
[count
- 1] = UlongToHandle( tmp
);
1303 if (count
== size
) break;
1312 /****************************************************************************
1313 * NtUserGetKeyboardLayoutName (win32u.@)
1315 BOOL WINAPI
NtUserGetKeyboardLayoutName( WCHAR
*name
)
1317 struct user_thread_info
*info
= get_user_thread_info();
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
];
1327 TRACE_(keyboard
)( "name %p\n", name
);
1331 RtlSetLastWin32Error( ERROR_NOACCESS
);
1335 if (info
->kbd_layout_id
)
1337 sprintf( buffer
, "%08X", info
->kbd_layout_id
);
1338 asciiz_to_unicode( name
, buffer
);
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);
1360 id
= wcstoul( klid
, NULL
, 16 );
1363 if (HIWORD( layout
) == id
)
1365 lstrcpynW( name
, klid
, KL_NAMELENGTH
);
1372 info
->kbd_layout_id
= wcstoul( name
, NULL
, 16 );
1374 TRACE_(keyboard
)( "ret %s\n", debugstr_w( name
) );
1378 /***********************************************************************
1379 * NtUserRegisterHotKey (win32u.@)
1381 BOOL WINAPI
NtUserRegisterHotKey( HWND hwnd
, INT id
, UINT modifiers
, UINT vk
)
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
))
1392 SERVER_START_REQ( register_hotkey
)
1394 req
->window
= wine_server_user_handle( hwnd
);
1396 req
->flags
= modifiers
;
1398 if ((ret
= !wine_server_call_err( req
)))
1400 replaced
= reply
->replaced
;
1401 modifiers
= reply
->flags
;
1407 if (ret
&& replaced
)
1408 user_driver
->pUnregisterHotKey(hwnd
, modifiers
, vk
);
1413 /***********************************************************************
1414 * NtUserUnregisterHotKey (win32u.@)
1416 BOOL WINAPI
NtUserUnregisterHotKey( HWND hwnd
, INT id
)
1421 TRACE_(keyboard
)("(%p,%d)\n",hwnd
,id
);
1423 SERVER_START_REQ( unregister_hotkey
)
1425 req
->window
= wine_server_user_handle( hwnd
);
1427 if ((ret
= !wine_server_call_err( req
)))
1429 modifiers
= reply
->flags
;
1436 user_driver
->pUnregisterHotKey(hwnd
, modifiers
, vk
);
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];
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
);
1460 if (!ptin
|| (!ptout
&& count
))
1462 RtlSetLastWin32Error( ERROR_NOACCESS
);
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
);
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;
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
))
1487 if (i
== ARRAY_SIZE( positions
))
1489 RtlSetLastWin32Error( ERROR_POINT_NOT_FOUND
);
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
;
1505 static WORD
get_key_state(void)
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
;
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
;
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 );
1543 NtUserPostMessage( tracking_info
.info
.hwndTrack
, WM_MOUSELEAVE
, 0, 0 );
1545 tracking_info
.info
.dwFlags
&= ~TME_LEAVE
;
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
;
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
;
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
;
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
) );
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
)
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
);
1653 if (info
->dwFlags
& TME_QUERY
)
1655 *info
= tracking_info
.info
;
1656 info
->cbSize
= sizeof(TRACKMOUSEEVENT
);
1660 if (!is_window( info
->hwndTrack
))
1662 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
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;
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
);
1723 /**********************************************************************
1724 * set_capture_window
1726 BOOL
set_capture_window( HWND hwnd
, UINT gui_flags
, HWND
*prev_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
);
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
);
1749 user_driver
->pSetCapture( hwnd
, gui_flags
);
1752 send_message( previous
, WM_CAPTURECHANGED
, 0, (LPARAM
)hwnd
);
1754 if (prev_ret
) *prev_ret
= previous
;
1759 /**********************************************************************
1760 * NtUserSetCapture (win32u.@)
1762 HWND WINAPI
NtUserSetCapture( HWND hwnd
)
1766 set_capture_window( hwnd
, 0, &previous
);
1770 /**********************************************************************
1773 BOOL
release_capture(void)
1775 BOOL ret
= set_capture_window( 0, 0, NULL
);
1777 /* Somebody may have missed some mouse movements */
1780 INPUT input
= { .type
= INPUT_MOUSE
};
1781 input
.mi
.dwFlags
= MOUSEEVENTF_MOVE
;
1782 NtUserSendInput( 1, &input
, sizeof(input
) );
1788 /*****************************************************************
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
;
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
);
1806 if (previous
== hwnd
) return previous
;
1810 send_message( previous
, WM_KILLFOCUS
, (WPARAM
)hwnd
, 0 );
1812 ime_hwnd
= get_default_ime_window( previous
);
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
);
1825 send_message( ime_hwnd
, WM_IME_INTERNAL
, IME_INTERNAL_ACTIVATE
,
1826 HandleToUlong(hwnd
) );
1829 NtUserNotifyWinEvent( EVENT_OBJECT_FOCUS
, hwnd
, OBJID_CLIENT
, 0 );
1831 send_message( hwnd
, WM_SETFOCUS
, (WPARAM
)previous
, 0 );
1836 /*******************************************************************
1839 static BOOL
set_active_window( HWND hwnd
, HWND
*prev
, BOOL mouse
, BOOL focus
)
1841 HWND previous
= get_active_window();
1843 DWORD old_thread
, new_thread
;
1844 CBTACTIVATESTRUCT cbt
;
1846 if (previous
== hwnd
)
1848 if (prev
) *prev
= hwnd
;
1852 /* call CBT hook chain */
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
);
1871 if (!ret
) return FALSE
;
1872 if (prev
) *prev
= previous
;
1873 if (previous
== hwnd
) goto done
;
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
)
1891 if ((list
= list_window_children( NULL
, get_desktop_window(), NULL
, 0 )))
1895 for (phwnd
= list
; *phwnd
; phwnd
++)
1897 if (get_window_thread( *phwnd
, NULL
) == old_thread
)
1898 send_message( *phwnd
, WM_ACTIVATEAPP
, 0, 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
);
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
) ),
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 */
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
);
1939 if (hwnd
) clip_fullscreen_window( hwnd
, FALSE
);
1943 /**********************************************************************
1944 * NtUserSetActiveWindow (win32u.@)
1946 HWND WINAPI
NtUserSetActiveWindow( HWND hwnd
)
1950 TRACE( "%p\n", hwnd
);
1956 hwnd
= get_full_window_handle( hwnd
);
1957 if (!is_window( hwnd
))
1959 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
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;
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
);
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
);
1991 if (hwnd
== previous
) return previous
; /* nothing to do */
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;
2004 if (parent
== get_hwnd_message_parent()) return 0;
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
;
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
;
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
);
2073 unsigned int timeout
;
2076 static void display_caret( HWND hwnd
, const RECT
*r
)
2080 /* do not use DCX_CACHE here, since coördinates are in logical units */
2081 if (!(dc
= NtUserGetDCEx( hwnd
, 0, DCX_USESTYLE
)))
2083 mem_dc
= NtGdiCreateCompatibleDC(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;
2103 if (!(key
= reg_open_hkcu_key( "Control Panel\\Desktop" )))
2106 if (query_reg_ascii_value( key
, "CursorBlinkRate", value
, sizeof(value_buffer
) ))
2107 ret
= wcstoul( (WCHAR
*)value
->Data
, NULL
, 10 );
2112 /*****************************************************************
2113 * NtUserCreateCaret (win32u.@)
2115 BOOL WINAPI
NtUserCreateCaret( HWND hwnd
, HBITMAP bitmap
, int width
, int height
)
2117 HBITMAP caret_bitmap
= 0;
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)
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
);
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
);
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
);
2158 HDC mem_dc
= NtGdiCreateCompatibleDC( 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
);
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
;
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();
2207 /*******************************************************************
2210 BOOL
destroy_caret(void)
2218 SERVER_START_REQ( set_caret_window
)
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
;
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
);
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 */
2267 /*****************************************************************
2268 * NtUserGetCaretPos (win32u.@)
2270 BOOL WINAPI
NtUserGetCaretPos( POINT
*pt
)
2274 SERVER_START_REQ( set_caret_info
)
2276 req
->flags
= 0; /* don't set anything */
2282 if ((ret
= !wine_server_call_err( req
)))
2284 pt
->x
= reply
->old_rect
.left
;
2285 pt
->y
= reply
->old_rect
.top
;
2292 /*******************************************************************
2295 BOOL
set_caret_pos( int x
, int y
)
2303 TRACE( "(%d, %d)\n", x
, y
);
2305 SERVER_START_REQ( set_caret_info
)
2307 req
->flags
= SET_CARET_POS
|SET_CARET_STATE
;
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
;
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
;
2332 display_caret( hwnd
, &r
);
2333 NtUserSetSystemTimer( hwnd
, SYSTEM_TIMER_CARET
, caret
.timeout
);
2338 /*****************************************************************
2339 * NtUserShowCaret (win32u.@)
2341 BOOL WINAPI
NtUserShowCaret( HWND hwnd
)
2347 SERVER_START_REQ( set_caret_info
)
2349 req
->flags
= SET_CARET_HIDE
| SET_CARET_STATE
;
2350 req
->handle
= wine_server_user_handle( hwnd
);
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
;
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
);
2375 /*****************************************************************
2376 * NtUserHideCaret (win32u.@)
2378 BOOL WINAPI
NtUserHideCaret( HWND hwnd
)
2385 SERVER_START_REQ( set_caret_info
)
2387 req
->flags
= SET_CARET_HIDE
| SET_CARET_STATE
;
2388 req
->handle
= wine_server_user_handle( hwnd
);
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
;
2408 if (old_state
) display_caret( hwnd
, &r
);
2409 kill_system_timer( hwnd
, SYSTEM_TIMER_CARET
);
2414 void toggle_caret( HWND hwnd
)
2420 SERVER_START_REQ( set_caret_info
)
2422 req
->flags
= SET_CARET_STATE
;
2423 req
->handle
= wine_server_user_handle( hwnd
);
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
;
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
);
2454 /**********************************************************************
2455 * NtUserIsMouseInPointerEnabled (win32u.@)
2457 BOOL WINAPI
NtUserIsMouseInPointerEnabled(void)
2460 RtlSetLastWin32Error( ERROR_CALL_NOT_IMPLEMENTED
);
2464 static BOOL
is_captured_by_system(void)
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
)};
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
);
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
);
2537 BOOL
get_clip_cursor( RECT
*rect
)
2542 if (!rect
) return FALSE
;
2544 SERVER_START_REQ( set_cursor
)
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
;
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
);
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
;
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
;
2601 /***********************************************************************
2602 * NtUserClipCursor (win32u.@)
2604 BOOL WINAPI
NtUserClipCursor( const RECT
*rect
)
2610 TRACE( "Clipping to %s\n", wine_dbgstr_rect(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
));
2623 SERVER_START_REQ( set_cursor
)
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
);