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 BOOL grab_pointer
= TRUE
;
410 BOOL grab_fullscreen
= FALSE
;
412 static void kbd_tables_init_vsc2vk( const KBDTABLES
*tables
, USHORT vsc2vk
[0x300] )
417 memset( vsc2vk
, 0, 0x300 * sizeof(USHORT
) );
419 for (vsc
= 0; tables
->pusVSCtoVK
&& vsc
<= tables
->bMaxVSCtoVK
; ++vsc
)
421 if (tables
->pusVSCtoVK
[vsc
] == VK__none_
) continue;
422 vsc2vk
[vsc
] = tables
->pusVSCtoVK
[vsc
];
424 for (entry
= tables
->pVSCtoVK_E0
; entry
&& entry
->Vsc
; entry
++)
426 if (entry
->Vk
== VK__none_
) continue;
427 vsc2vk
[entry
->Vsc
+ 0x100] = entry
->Vk
;
429 for (entry
= tables
->pVSCtoVK_E1
; entry
&& entry
->Vsc
; entry
++)
431 if (entry
->Vk
== VK__none_
) continue;
432 vsc2vk
[entry
->Vsc
+ 0x200] = entry
->Vk
;
436 #define NEXT_ENTRY(t, e) ((void *)&(e)->wch[(t)->nModifications])
438 static void kbd_tables_init_vk2char( const KBDTABLES
*tables
, BYTE vk2char
[0x100] )
440 const VK_TO_WCHAR_TABLE
*table
;
441 const VK_TO_WCHARS1
*entry
;
443 memset( vk2char
, 0, 0x100 );
445 for (table
= tables
->pVkToWcharTable
; table
->pVkToWchars
; table
++)
447 for (entry
= table
->pVkToWchars
; entry
->VirtualKey
; entry
= NEXT_ENTRY(table
, entry
))
449 if (entry
->VirtualKey
& ~0xff) continue;
450 vk2char
[entry
->VirtualKey
] = entry
->wch
[0];
455 static UINT
kbd_tables_get_mod_bits( const KBDTABLES
*tables
, UINT mod
)
457 const MODIFIERS
*mods
= tables
->pCharModifiers
;
460 for (bits
= 0; bits
<= mods
->wMaxModBits
; ++bits
)
461 if (mods
->ModNumber
[bits
] == mod
) return bits
;
466 static UINT
kbd_tables_get_mod_num( const KBDTABLES
*tables
, const BYTE
*state
, BOOL caps
)
468 const MODIFIERS
*mods
= tables
->pCharModifiers
;
469 const VK_TO_BIT
*entry
;
472 for (entry
= mods
->pVkToBit
; entry
->Vk
; ++entry
)
473 if (state
[entry
->Vk
] & 0x80) bits
|= entry
->ModBits
;
474 if (caps
) bits
|= KBDSHIFT
;
476 if (bits
> mods
->wMaxModBits
) return -1;
477 return mods
->ModNumber
[bits
];
480 static WORD
kbd_tables_wchar_to_vkey( const KBDTABLES
*tables
, WCHAR wch
)
482 const VK_TO_WCHAR_TABLE
*table
;
483 const VK_TO_WCHARS1
*entry
;
487 if (wch
== '\x001b') return VK_ESCAPE
;
489 for (table
= tables
->pVkToWcharTable
; table
->pVkToWchars
; table
++)
491 for (entry
= table
->pVkToWchars
; entry
->VirtualKey
; entry
= NEXT_ENTRY(table
, entry
))
493 for (mod
= 0; mod
< table
->nModifications
; ++mod
)
495 if (entry
->wch
[mod
] == WCH_NONE
|| entry
->wch
[mod
] != wch
) continue;
496 bits
= kbd_tables_get_mod_bits( tables
, mod
);
497 return (bits
<< 8) | entry
->VirtualKey
;
502 if (wch
>= 0x0001 && wch
<= 0x001a) return (0x200) | ('A' + wch
- 1); /* CTRL + A-Z */
503 return wch
>= 0x0080 ? -1 : 0;
506 static WCHAR
kbd_tables_vkey_to_wchar( const KBDTABLES
*tables
, UINT vkey
, const BYTE
*state
)
508 UINT mod
, caps_mod
, alt
, ctrl
, caps
;
509 const VK_TO_WCHAR_TABLE
*table
;
510 const VK_TO_WCHARS1
*entry
;
512 alt
= state
[VK_MENU
] & 0x80;
513 ctrl
= state
[VK_CONTROL
] & 0x80;
514 caps
= state
[VK_CAPITAL
] & 1;
516 if (ctrl
&& alt
&& !(tables
->fLocaleFlags
& KLLF_ALTGR
)) return WCH_NONE
;
517 if (!ctrl
&& vkey
== VK_ESCAPE
) return VK_ESCAPE
;
520 if (vkey
>= 'A' && vkey
<= 'Z') return vkey
- 'A' + 1;
521 tables
= &kbdus_tables
;
523 if (vkey
>= VK_NUMPAD0
&& vkey
<= VK_NUMPAD9
) tables
= &kbdus_tables
;
525 mod
= caps_mod
= kbd_tables_get_mod_num( tables
, state
, FALSE
);
526 if (caps
) caps_mod
= kbd_tables_get_mod_num( tables
, state
, TRUE
);
528 for (table
= tables
->pVkToWcharTable
; table
->pVkToWchars
; table
++)
530 if (table
->nModifications
<= mod
) continue;
531 for (entry
= table
->pVkToWchars
; entry
->VirtualKey
; entry
= NEXT_ENTRY(table
, entry
))
533 if (entry
->VirtualKey
!= vkey
) continue;
534 /* SGCAPS attribute may be set on entries where VK_CAPITAL and VK_SHIFT behave differently.
535 * The entry corresponds to the mapping when Caps Lock is on, and a second entry follows it
536 * with the mapping when Caps Lock is off.
538 if ((entry
->Attributes
& SGCAPS
) && !caps
) entry
= NEXT_ENTRY(table
, entry
);
539 if ((entry
->Attributes
& CAPLOK
) && table
->nModifications
> caps_mod
) return entry
->wch
[caps_mod
];
540 return entry
->wch
[mod
];
549 /*******************************************************************
550 * NtUserGetForegroundWindow (win32u.@)
552 HWND WINAPI
NtUserGetForegroundWindow(void)
554 struct object_lock lock
= OBJECT_LOCK_INIT
;
555 const input_shm_t
*input_shm
;
559 while ((status
= get_shared_input( 0, &lock
, &input_shm
)) == STATUS_PENDING
)
560 hwnd
= wine_server_ptr_handle( input_shm
->active
);
561 if (status
) hwnd
= 0;
566 /* see GetActiveWindow */
567 HWND
get_active_window(void)
570 info
.cbSize
= sizeof(info
);
571 return NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info
) ? info
.hwndActive
: 0;
575 HWND
get_capture(void)
578 info
.cbSize
= sizeof(info
);
579 return NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info
) ? info
.hwndCapture
: 0;
586 info
.cbSize
= sizeof(info
);
587 return NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info
) ? info
.hwndFocus
: 0;
590 /**********************************************************************
591 * NtUserAttachThreadInput (win32u.@)
593 BOOL WINAPI
NtUserAttachThreadInput( DWORD from
, DWORD to
, BOOL attach
)
597 SERVER_START_REQ( attach_thread_input
)
599 req
->tid_from
= from
;
601 req
->attach
= attach
;
602 ret
= !wine_server_call_err( req
);
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, SEND_HWMSG_INJECTED
, &input
, 0 );
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
)
743 struct object_lock lock
= OBJECT_LOCK_INIT
;
744 const desktop_shm_t
*desktop_shm
;
746 DWORD last_change
= 0;
750 if (!pt
) return FALSE
;
752 while ((status
= get_shared_desktop( &lock
, &desktop_shm
)) == STATUS_PENDING
)
754 pt
->x
= desktop_shm
->cursor
.x
;
755 pt
->y
= desktop_shm
->cursor
.y
;
756 last_change
= desktop_shm
->cursor
.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
)
775 struct object_lock lock
= OBJECT_LOCK_INIT
;
776 const input_shm_t
*input_shm
;
779 if (!info
) return FALSE
;
781 while ((status
= get_shared_input( 0, &lock
, &input_shm
)) == STATUS_PENDING
)
783 info
->hCursor
= wine_server_ptr_handle( input_shm
->cursor
);
784 info
->flags
= (input_shm
->cursor_count
>= 0) ? CURSOR_SHOWING
: 0;
789 info
->flags
= CURSOR_SHOWING
;
792 get_cursor_pos( &info
->ptScreenPos
);
796 static void check_for_events( UINT flags
)
798 struct peek_message_filter filter
=
805 if (!user_driver
->pProcessEvents( flags
))
806 flush_window_surfaces( TRUE
);
808 peek_message( &msg
, &filter
);
811 /**********************************************************************
812 * GetAsyncKeyState (win32u.@)
814 SHORT WINAPI
NtUserGetAsyncKeyState( INT key
)
816 const desktop_shm_t
*desktop_shm
;
817 struct object_lock lock
= OBJECT_LOCK_INIT
;
822 if (key
< 0 || key
>= 256) return 0;
824 check_for_events( QS_INPUT
);
826 while ((status
= get_shared_desktop( &lock
, &desktop_shm
)) == STATUS_PENDING
)
827 state
= desktop_shm
->keystate
[key
];
829 if (status
) return 0;
830 if (!(state
& 0x40)) return (state
& 0x80) << 8;
832 /* Need to make a server call to reset the last pressed bit */
833 SERVER_START_REQ( get_key_state
)
837 if (!wine_server_call( req
))
839 if (reply
->state
& 0x40) ret
|= 0x0001;
840 if (reply
->state
& 0x80) ret
|= 0x8000;
848 /***********************************************************************
849 * get_shared_queue_bits
851 static BOOL
get_shared_queue_bits( UINT
*wake_bits
, UINT
*changed_bits
)
853 struct object_lock lock
= OBJECT_LOCK_INIT
;
854 const queue_shm_t
*queue_shm
;
857 *wake_bits
= *changed_bits
= 0;
858 while ((status
= get_shared_queue( &lock
, &queue_shm
)) == STATUS_PENDING
)
860 *wake_bits
= queue_shm
->wake_bits
;
861 *changed_bits
= queue_shm
->changed_bits
;
864 if (status
) return FALSE
;
868 /***********************************************************************
869 * NtUserGetQueueStatus (win32u.@)
871 DWORD WINAPI
NtUserGetQueueStatus( UINT flags
)
873 UINT ret
, wake_bits
, changed_bits
;
875 if (flags
& ~(QS_ALLINPUT
| QS_ALLPOSTMESSAGE
| QS_SMRESULT
))
877 RtlSetLastWin32Error( ERROR_INVALID_FLAGS
);
881 check_for_events( flags
);
883 if (get_shared_queue_bits( &wake_bits
, &changed_bits
) && !(changed_bits
& flags
))
884 ret
= MAKELONG( changed_bits
& flags
, wake_bits
& flags
);
885 else SERVER_START_REQ( get_queue_status
)
887 req
->clear_bits
= flags
;
888 wine_server_call( req
);
889 ret
= MAKELONG( reply
->changed_bits
& flags
, reply
->wake_bits
& flags
);
895 /***********************************************************************
898 DWORD
get_input_state(void)
900 UINT wake_bits
, changed_bits
;
902 check_for_events( QS_INPUT
);
904 if (!get_shared_queue_bits( &wake_bits
, &changed_bits
)) return 0;
905 return wake_bits
& (QS_KEY
| QS_MOUSEBUTTON
);
908 /***********************************************************************
909 * get_locale_kbd_layout
911 static HKL
get_locale_kbd_layout(void)
917 * layout = main_key_tab[kbd_layout].lcid;
919 * Winword uses return value of GetKeyboardLayout as a codepage
920 * to translate ANSI keyboard messages to unicode. But we have
921 * a problem with it: for instance Polish keyboard layout is
922 * identical to the US one, and therefore instead of the Polish
923 * locale id we return the US one.
926 NtQueryDefaultLocale( TRUE
, &layout
);
927 layout
= MAKELONG( layout
, layout
);
928 return ULongToHandle( layout
);
931 /***********************************************************************
932 * NtUserGetKeyboardLayout (win32u.@)
934 * Device handle for keyboard layout defaulted to
935 * the language id. This is the way Windows default works.
937 HKL WINAPI
NtUserGetKeyboardLayout( DWORD thread_id
)
939 struct user_thread_info
*thread
= get_user_thread_info();
940 HKL layout
= thread
->kbd_layout
;
942 if (thread_id
&& thread_id
!= GetCurrentThreadId())
943 FIXME( "couldn't return keyboard layout for thread %04x\n", (int)thread_id
);
945 if (!layout
) return get_locale_kbd_layout();
949 /**********************************************************************
950 * NtUserGetKeyState (win32u.@)
952 * An application calls the GetKeyState function in response to a
953 * keyboard-input message. This function retrieves the state of the key
954 * at the time the input message was generated.
956 SHORT WINAPI
NtUserGetKeyState( INT vkey
)
960 SERVER_START_REQ( get_key_state
)
963 if (!wine_server_call( req
)) retval
= (signed char)(reply
->state
& 0x81);
966 TRACE("key (0x%x) -> %x\n", vkey
, retval
);
970 /**********************************************************************
971 * NtUserGetKeyboardState (win32u.@)
973 BOOL WINAPI
NtUserGetKeyboardState( BYTE
*state
)
978 TRACE("(%p)\n", state
);
980 memset( state
, 0, 256 );
981 SERVER_START_REQ( get_key_state
)
984 wine_server_set_reply( req
, state
, 256 );
985 ret
= !wine_server_call_err( req
);
986 for (i
= 0; i
< 256; i
++) state
[i
] &= 0x81;
992 /**********************************************************************
993 * NtUserSetKeyboardState (win32u.@)
995 BOOL WINAPI
NtUserSetKeyboardState( BYTE
*state
)
999 SERVER_START_REQ( set_key_state
)
1001 wine_server_add_data( req
, state
, 256 );
1002 ret
= !wine_server_call_err( req
);
1008 /******************************************************************************
1009 * NtUserVkKeyScanEx (win32u.@)
1011 WORD WINAPI
NtUserVkKeyScanEx( WCHAR chr
, HKL layout
)
1013 const KBDTABLES
*kbd_tables
;
1016 TRACE_(keyboard
)( "chr %s, layout %p\n", debugstr_wn(&chr
, 1), layout
);
1018 if ((ret
= user_driver
->pVkKeyScanEx( chr
, layout
)) != -256) return ret
;
1020 if (!(kbd_tables
= user_driver
->pKbdLayerDescriptor( layout
))) kbd_tables
= &kbdus_tables
;
1021 ret
= kbd_tables_wchar_to_vkey( kbd_tables
, chr
);
1022 if (kbd_tables
!= &kbdus_tables
) user_driver
->pReleaseKbdTables( kbd_tables
);
1024 TRACE_(keyboard
)( "ret %04x\n", ret
);
1029 /******************************************************************************
1030 * NtUserMapVirtualKeyEx (win32u.@)
1032 UINT WINAPI
NtUserMapVirtualKeyEx( UINT code
, UINT type
, HKL layout
)
1034 USHORT vsc2vk
[0x300];
1035 BYTE vk2char
[0x100];
1036 const KBDTABLES
*kbd_tables
;
1039 TRACE_(keyboard
)( "code %u, type %u, layout %p.\n", code
, type
, layout
);
1041 if ((ret
= user_driver
->pMapVirtualKeyEx( code
, type
, layout
)) != -1) return ret
;
1043 if (!(kbd_tables
= user_driver
->pKbdLayerDescriptor( layout
))) kbd_tables
= &kbdus_tables
;
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
] & 0xff) == 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
] & 0xff;
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 if (kbd_tables
!= &kbdus_tables
) user_driver
->pReleaseKbdTables( kbd_tables
);
1109 TRACE_(keyboard
)( "returning 0x%04x\n", ret
);
1113 /***********************************************************************
1114 * map_scan_to_kbd_vkey
1116 * Map a scancode to a virtual key with KBD information.
1118 USHORT
map_scan_to_kbd_vkey( USHORT scan
, HKL layout
)
1120 const KBDTABLES
*kbd_tables
;
1121 USHORT vsc2vk
[0x300];
1124 if ((vkey
= user_driver
->pMapVirtualKeyEx( scan
, MAPVK_VSC_TO_VK_EX
, layout
)) != -1) return vkey
;
1126 if (!(kbd_tables
= user_driver
->pKbdLayerDescriptor( layout
))) kbd_tables
= &kbdus_tables
;
1128 kbd_tables_init_vsc2vk( kbd_tables
, vsc2vk
);
1129 if (scan
& 0xe000) scan
-= 0xdf00;
1130 if (scan
>= ARRAY_SIZE(vsc2vk
)) vkey
= 0;
1131 else vkey
= vsc2vk
[scan
];
1133 if (kbd_tables
!= &kbdus_tables
) user_driver
->pReleaseKbdTables( kbd_tables
);
1138 /****************************************************************************
1139 * NtUserGetKeyNameText (win32u.@)
1141 INT WINAPI
NtUserGetKeyNameText( LONG lparam
, WCHAR
*buffer
, INT size
)
1143 INT code
= ((lparam
>> 16) & 0x1ff), vkey
, len
;
1144 HKL layout
= NtUserGetKeyboardLayout( 0 );
1145 const KBDTABLES
*kbd_tables
;
1146 VSC_LPWSTR
*key_name
;
1148 TRACE_(keyboard
)( "lparam %#x, buffer %p, size %d.\n", (int)lparam
, buffer
, size
);
1150 if (!buffer
|| !size
) return 0;
1151 if ((len
= user_driver
->pGetKeyNameText( lparam
, buffer
, size
)) >= 0) return len
;
1153 if (!(kbd_tables
= user_driver
->pKbdLayerDescriptor( layout
))) kbd_tables
= &kbdus_tables
;
1155 if (lparam
& 0x2000000)
1157 USHORT vsc2vk
[0x300];
1158 kbd_tables_init_vsc2vk( kbd_tables
, vsc2vk
);
1159 switch ((vkey
= vsc2vk
[code
] & 0xff))
1164 for (code
= 0; code
< ARRAY_SIZE(vsc2vk
); ++code
)
1165 if ((vsc2vk
[code
] & 0xff) == (vkey
- 1)) break;
1170 if (code
< 0x100) key_name
= kbd_tables
->pKeyNames
;
1171 else key_name
= kbd_tables
->pKeyNamesExt
;
1172 while (key_name
->vsc
&& key_name
->vsc
!= (BYTE
)code
) key_name
++;
1174 if (key_name
->vsc
== (BYTE
)code
&& key_name
->pwsz
)
1176 len
= min( size
- 1, wcslen( key_name
->pwsz
) );
1177 memcpy( buffer
, key_name
->pwsz
, len
* sizeof(WCHAR
) );
1181 HKL hkl
= NtUserGetKeyboardLayout( 0 );
1182 vkey
= NtUserMapVirtualKeyEx( code
& 0xff, MAPVK_VSC_TO_VK
, hkl
);
1183 buffer
[0] = NtUserMapVirtualKeyEx( vkey
, MAPVK_VK_TO_CHAR
, hkl
);
1188 if (kbd_tables
!= &kbdus_tables
) user_driver
->pReleaseKbdTables( kbd_tables
);
1190 TRACE_(keyboard
)( "ret %d, str %s.\n", len
, debugstr_w(buffer
) );
1194 /****************************************************************************
1195 * NtUserToUnicodeEx (win32u.@)
1197 INT WINAPI
NtUserToUnicodeEx( UINT virt
, UINT scan
, const BYTE
*state
,
1198 WCHAR
*str
, int size
, UINT flags
, HKL layout
)
1200 const KBDTABLES
*kbd_tables
;
1203 TRACE_(keyboard
)( "virt %#x, scan %#x, state %p, str %p, size %d, flags %#x, layout %p.\n",
1204 virt
, scan
, state
, str
, size
, flags
, layout
);
1206 if (!state
|| !size
) return 0;
1207 if ((len
= user_driver
->pToUnicodeEx( virt
, scan
, state
, str
, size
, flags
, layout
)) >= -1) return len
;
1209 if (!(kbd_tables
= user_driver
->pKbdLayerDescriptor( layout
))) kbd_tables
= &kbdus_tables
;
1210 if (scan
& 0x8000) str
[0] = 0; /* key up */
1211 else str
[0] = kbd_tables_vkey_to_wchar( kbd_tables
, virt
, state
);
1212 if (size
> 1) str
[1] = 0;
1214 if (str
[0] != WCH_NONE
) len
= 1;
1215 else str
[0] = len
= 0;
1217 if (kbd_tables
!= &kbdus_tables
) user_driver
->pReleaseKbdTables( kbd_tables
);
1219 TRACE_(keyboard
)( "ret %d, str %s.\n", len
, debugstr_wn(str
, len
) );
1223 /**********************************************************************
1224 * NtUserActivateKeyboardLayout (win32u.@)
1226 HKL WINAPI
NtUserActivateKeyboardLayout( HKL layout
, UINT flags
)
1228 struct user_thread_info
*info
= get_user_thread_info();
1233 TRACE_(keyboard
)( "layout %p, flags %x\n", layout
, flags
);
1235 if (flags
) FIXME_(keyboard
)( "flags %x not supported\n", flags
);
1237 if (layout
== (HKL
)HKL_NEXT
|| layout
== (HKL
)HKL_PREV
)
1239 RtlSetLastWin32Error( ERROR_CALL_NOT_IMPLEMENTED
);
1240 FIXME_(keyboard
)( "HKL_NEXT and HKL_PREV not supported\n" );
1244 if (LOWORD(layout
) != MAKELANGID(LANG_INVARIANT
, SUBLANG_DEFAULT
) &&
1245 (NtQueryDefaultLocale( TRUE
, &locale
) || LOWORD(layout
) != locale
))
1247 RtlSetLastWin32Error( ERROR_CALL_NOT_IMPLEMENTED
);
1248 FIXME_(keyboard
)( "Changing user locale is not supported\n" );
1252 if (!user_driver
->pActivateKeyboardLayout( layout
, flags
))
1255 old_layout
= info
->kbd_layout
;
1256 if (old_layout
!= layout
)
1258 HWND ime_hwnd
= get_default_ime_window( 0 );
1259 const NLS_LOCALE_DATA
*data
;
1260 CHARSETINFO cs
= {0};
1262 if (ime_hwnd
) send_message( ime_hwnd
, WM_IME_INTERNAL
, IME_INTERNAL_HKL_DEACTIVATE
, HandleToUlong(old_layout
) );
1264 if (HIWORD(layout
) & 0x8000)
1265 FIXME( "Aliased keyboard layout not yet implemented\n" );
1266 else if (!(data
= get_locale_data( HIWORD(layout
) )))
1267 WARN( "Failed to find locale data for %04x\n", HIWORD(layout
) );
1269 translate_charset_info( ULongToPtr(data
->idefaultansicodepage
), &cs
, TCI_SRCCODEPAGE
);
1271 info
->kbd_layout
= layout
;
1272 info
->kbd_layout_id
= 0;
1274 if (ime_hwnd
) send_message( ime_hwnd
, WM_IME_INTERNAL
, IME_INTERNAL_HKL_ACTIVATE
, HandleToUlong(layout
) );
1276 if ((focus
= get_focus()) && get_window_thread( focus
, NULL
) == GetCurrentThreadId())
1277 send_message( focus
, WM_INPUTLANGCHANGE
, cs
.ciCharset
, (LPARAM
)layout
);
1280 if (!old_layout
) return get_locale_kbd_layout();
1286 /***********************************************************************
1287 * NtUserGetKeyboardLayoutList (win32u.@)
1289 * Return number of values available if either input parm is
1290 * 0, per MS documentation.
1292 UINT WINAPI
NtUserGetKeyboardLayoutList( INT size
, HKL
*layouts
)
1295 KEY_NODE_INFORMATION
*key_info
= (KEY_NODE_INFORMATION
*)buffer
;
1296 KEY_VALUE_PARTIAL_INFORMATION
*value_info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
1297 DWORD count
, tmp
, i
= 0;
1301 TRACE_(keyboard
)( "size %d, layouts %p.\n", size
, layouts
);
1303 if ((count
= user_driver
->pGetKeyboardLayoutList( size
, layouts
)) != ~0) return count
;
1305 layout
= get_locale_kbd_layout();
1309 if (size
&& layouts
)
1311 layouts
[count
- 1] = layout
;
1312 if (count
== size
) return count
;
1315 if ((hkey
= reg_open_key( NULL
, keyboard_layouts_keyW
, sizeof(keyboard_layouts_keyW
) )))
1317 while (!NtEnumerateKey( hkey
, i
++, KeyNodeInformation
, key_info
,
1318 sizeof(buffer
) - sizeof(WCHAR
), &tmp
))
1320 if (!(subkey
= reg_open_key( hkey
, key_info
->Name
, key_info
->NameLength
))) continue;
1321 key_info
->Name
[key_info
->NameLength
/ sizeof(WCHAR
)] = 0;
1322 tmp
= wcstoul( key_info
->Name
, NULL
, 16 );
1323 if (query_reg_ascii_value( subkey
, "Layout Id", value_info
, sizeof(buffer
) ) &&
1324 value_info
->Type
== REG_SZ
)
1325 tmp
= 0xf000 | (wcstoul( (const WCHAR
*)value_info
->Data
, NULL
, 16 ) & 0xfff);
1328 tmp
= MAKELONG( LOWORD( layout
), LOWORD( tmp
) );
1329 if (layout
== UlongToHandle( tmp
)) continue;
1332 if (size
&& layouts
)
1334 layouts
[count
- 1] = UlongToHandle( tmp
);
1335 if (count
== size
) break;
1344 /****************************************************************************
1345 * NtUserGetKeyboardLayoutName (win32u.@)
1347 BOOL WINAPI
NtUserGetKeyboardLayoutName( WCHAR
*name
)
1349 struct user_thread_info
*info
= get_user_thread_info();
1351 KEY_NODE_INFORMATION
*key
= (KEY_NODE_INFORMATION
*)buffer
;
1352 KEY_VALUE_PARTIAL_INFORMATION
*value
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
1353 WCHAR klid
[KL_NAMELENGTH
];
1359 TRACE_(keyboard
)( "name %p\n", name
);
1363 RtlSetLastWin32Error( ERROR_NOACCESS
);
1367 if (info
->kbd_layout_id
)
1369 snprintf( buffer
, sizeof(buffer
), "%08X", info
->kbd_layout_id
);
1370 asciiz_to_unicode( name
, buffer
);
1374 layout
= NtUserGetKeyboardLayout( 0 );
1375 id
= HandleToUlong( layout
);
1376 if (HIWORD( id
) == LOWORD( id
)) id
= LOWORD( id
);
1377 snprintf( buffer
, sizeof(buffer
), "%08X", id
);
1378 asciiz_to_unicode( name
, buffer
);
1380 if ((hkey
= reg_open_key( NULL
, keyboard_layouts_keyW
, sizeof(keyboard_layouts_keyW
) )))
1382 while (!NtEnumerateKey( hkey
, i
++, KeyNodeInformation
, key
,
1383 sizeof(buffer
) - sizeof(WCHAR
), &len
))
1385 if (!(subkey
= reg_open_key( hkey
, key
->Name
, key
->NameLength
))) continue;
1386 memcpy( klid
, key
->Name
, key
->NameLength
);
1387 klid
[key
->NameLength
/ sizeof(WCHAR
)] = 0;
1388 if (query_reg_ascii_value( subkey
, "Layout Id", value
, sizeof(buffer
) ) &&
1389 value
->Type
== REG_SZ
)
1390 id
= 0xf000 | (wcstoul( (const WCHAR
*)value
->Data
, NULL
, 16 ) & 0xfff);
1392 id
= wcstoul( klid
, NULL
, 16 );
1395 if (HIWORD( layout
) == id
)
1397 lstrcpynW( name
, klid
, KL_NAMELENGTH
);
1404 info
->kbd_layout_id
= wcstoul( name
, NULL
, 16 );
1406 TRACE_(keyboard
)( "ret %s\n", debugstr_w( name
) );
1410 /***********************************************************************
1411 * NtUserRegisterHotKey (win32u.@)
1413 BOOL WINAPI
NtUserRegisterHotKey( HWND hwnd
, INT id
, UINT modifiers
, UINT vk
)
1418 TRACE_(keyboard
)( "(%p,%d,0x%08x,%X)\n", hwnd
, id
, modifiers
, vk
);
1420 if ((!hwnd
|| is_current_thread_window( hwnd
)) &&
1421 !user_driver
->pRegisterHotKey( hwnd
, modifiers
, vk
))
1424 SERVER_START_REQ( register_hotkey
)
1426 req
->window
= wine_server_user_handle( hwnd
);
1428 req
->flags
= modifiers
;
1430 if ((ret
= !wine_server_call_err( req
)))
1432 replaced
= reply
->replaced
;
1433 modifiers
= reply
->flags
;
1439 if (ret
&& replaced
)
1440 user_driver
->pUnregisterHotKey(hwnd
, modifiers
, vk
);
1445 /***********************************************************************
1446 * NtUserUnregisterHotKey (win32u.@)
1448 BOOL WINAPI
NtUserUnregisterHotKey( HWND hwnd
, INT id
)
1453 TRACE_(keyboard
)("(%p,%d)\n",hwnd
,id
);
1455 SERVER_START_REQ( unregister_hotkey
)
1457 req
->window
= wine_server_user_handle( hwnd
);
1459 if ((ret
= !wine_server_call_err( req
)))
1461 modifiers
= reply
->flags
;
1468 user_driver
->pUnregisterHotKey(hwnd
, modifiers
, vk
);
1473 /***********************************************************************
1474 * NtUserGetMouseMovePointsEx (win32u.@)
1476 int WINAPI
NtUserGetMouseMovePointsEx( UINT size
, MOUSEMOVEPOINT
*ptin
, MOUSEMOVEPOINT
*ptout
,
1477 int count
, DWORD resolution
)
1479 cursor_pos_t
*pos
, positions
[64];
1484 TRACE( "%d, %p, %p, %d, %d\n", size
, ptin
, ptout
, count
, (int)resolution
);
1486 if ((size
!= sizeof(MOUSEMOVEPOINT
)) || (count
< 0) || (count
> ARRAY_SIZE( positions
)))
1488 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
1492 if (!ptin
|| (!ptout
&& count
))
1494 RtlSetLastWin32Error( ERROR_NOACCESS
);
1498 if (resolution
!= GMMP_USE_DISPLAY_POINTS
)
1500 FIXME( "only GMMP_USE_DISPLAY_POINTS is supported for now\n" );
1501 RtlSetLastWin32Error( ERROR_POINT_NOT_FOUND
);
1505 SERVER_START_REQ( get_cursor_history
)
1507 wine_server_set_reply( req
, &positions
, sizeof(positions
) );
1508 if (wine_server_call_err( req
)) return -1;
1512 for (i
= 0; i
< ARRAY_SIZE( positions
); i
++)
1514 pos
= &positions
[i
];
1515 if (ptin
->x
== pos
->x
&& ptin
->y
== pos
->y
&& (!ptin
->time
|| ptin
->time
== pos
->time
))
1519 if (i
== ARRAY_SIZE( positions
))
1521 RtlSetLastWin32Error( ERROR_POINT_NOT_FOUND
);
1525 for (copied
= 0; copied
< count
&& i
< ARRAY_SIZE( positions
); copied
++, i
++)
1527 pos
= &positions
[i
];
1528 ptout
[copied
].x
= pos
->x
;
1529 ptout
[copied
].y
= pos
->y
;
1530 ptout
[copied
].time
= pos
->time
;
1531 ptout
[copied
].dwExtraInfo
= pos
->info
;
1537 static WORD
get_key_state(void)
1541 if (get_system_metrics( SM_SWAPBUTTON
))
1543 if (NtUserGetAsyncKeyState(VK_RBUTTON
) & 0x80) ret
|= MK_LBUTTON
;
1544 if (NtUserGetAsyncKeyState(VK_LBUTTON
) & 0x80) ret
|= MK_RBUTTON
;
1548 if (NtUserGetAsyncKeyState(VK_LBUTTON
) & 0x80) ret
|= MK_LBUTTON
;
1549 if (NtUserGetAsyncKeyState(VK_RBUTTON
) & 0x80) ret
|= MK_RBUTTON
;
1551 if (NtUserGetAsyncKeyState(VK_MBUTTON
) & 0x80) ret
|= MK_MBUTTON
;
1552 if (NtUserGetAsyncKeyState(VK_SHIFT
) & 0x80) ret
|= MK_SHIFT
;
1553 if (NtUserGetAsyncKeyState(VK_CONTROL
) & 0x80) ret
|= MK_CONTROL
;
1554 if (NtUserGetAsyncKeyState(VK_XBUTTON1
) & 0x80) ret
|= MK_XBUTTON1
;
1555 if (NtUserGetAsyncKeyState(VK_XBUTTON2
) & 0x80) ret
|= MK_XBUTTON2
;
1559 struct tracking_list
1561 TRACKMOUSEEVENT info
;
1562 POINT pos
; /* center of hover rectangle */
1565 /* FIXME: move tracking stuff into per-thread data */
1566 static struct tracking_list tracking_info
;
1568 static void check_mouse_leave( HWND hwnd
, int hittest
)
1570 if (tracking_info
.info
.hwndTrack
!= hwnd
)
1572 if (tracking_info
.info
.dwFlags
& TME_NONCLIENT
)
1573 NtUserPostMessage( tracking_info
.info
.hwndTrack
, WM_NCMOUSELEAVE
, 0, 0 );
1575 NtUserPostMessage( tracking_info
.info
.hwndTrack
, WM_MOUSELEAVE
, 0, 0 );
1577 tracking_info
.info
.dwFlags
&= ~TME_LEAVE
;
1581 if (hittest
== HTCLIENT
)
1583 if (tracking_info
.info
.dwFlags
& TME_NONCLIENT
)
1585 NtUserPostMessage( tracking_info
.info
.hwndTrack
, WM_NCMOUSELEAVE
, 0, 0 );
1586 tracking_info
.info
.dwFlags
&= ~TME_LEAVE
;
1591 if (!(tracking_info
.info
.dwFlags
& TME_NONCLIENT
))
1593 NtUserPostMessage( tracking_info
.info
.hwndTrack
, WM_MOUSELEAVE
, 0, 0 );
1594 tracking_info
.info
.dwFlags
&= ~TME_LEAVE
;
1600 void update_mouse_tracking_info( HWND hwnd
)
1602 int hover_width
= 0, hover_height
= 0, hittest
;
1605 TRACE( "hwnd %p\n", hwnd
);
1607 get_cursor_pos( &pos
);
1608 hwnd
= window_from_point( hwnd
, pos
, &hittest
);
1610 TRACE( "point %s hwnd %p hittest %d\n", wine_dbgstr_point(&pos
), hwnd
, hittest
);
1612 NtUserSystemParametersInfo( SPI_GETMOUSEHOVERWIDTH
, 0, &hover_width
, 0 );
1613 NtUserSystemParametersInfo( SPI_GETMOUSEHOVERHEIGHT
, 0, &hover_height
, 0 );
1615 TRACE( "tracked pos %s, current pos %s, hover width %d, hover height %d\n",
1616 wine_dbgstr_point(&tracking_info
.pos
), wine_dbgstr_point(&pos
),
1617 hover_width
, hover_height
);
1619 if (tracking_info
.info
.dwFlags
& TME_LEAVE
)
1620 check_mouse_leave( hwnd
, hittest
);
1622 if (tracking_info
.info
.hwndTrack
!= hwnd
)
1623 tracking_info
.info
.dwFlags
&= ~TME_HOVER
;
1625 if (tracking_info
.info
.dwFlags
& TME_HOVER
)
1627 /* has the cursor moved outside the rectangle centered around pos? */
1628 if ((abs( pos
.x
- tracking_info
.pos
.x
) > (hover_width
/ 2)) ||
1629 (abs( pos
.y
- tracking_info
.pos
.y
) > (hover_height
/ 2)))
1631 tracking_info
.pos
= pos
;
1635 if (hittest
== HTCLIENT
)
1637 screen_to_client(hwnd
, &pos
);
1638 TRACE( "client cursor pos %s\n", wine_dbgstr_point(&pos
) );
1640 NtUserPostMessage( tracking_info
.info
.hwndTrack
, WM_MOUSEHOVER
,
1641 get_key_state(), MAKELPARAM( pos
.x
, pos
.y
) );
1645 if (tracking_info
.info
.dwFlags
& TME_NONCLIENT
)
1646 NtUserPostMessage( tracking_info
.info
.hwndTrack
, WM_NCMOUSEHOVER
,
1647 hittest
, MAKELPARAM( pos
.x
, pos
.y
) );
1650 /* stop tracking mouse hover */
1651 tracking_info
.info
.dwFlags
&= ~TME_HOVER
;
1655 /* stop the timer if the tracking list is empty */
1656 if (!(tracking_info
.info
.dwFlags
& (TME_HOVER
| TME_LEAVE
)))
1658 kill_system_timer( tracking_info
.info
.hwndTrack
, SYSTEM_TIMER_TRACK_MOUSE
);
1659 tracking_info
.info
.hwndTrack
= 0;
1660 tracking_info
.info
.dwFlags
= 0;
1661 tracking_info
.info
.dwHoverTime
= 0;
1665 /***********************************************************************
1666 * NtUserTrackMouseEvent (win32u.@)
1668 BOOL WINAPI
NtUserTrackMouseEvent( TRACKMOUSEEVENT
*info
)
1675 TRACE( "size %u, flags %#x, hwnd %p, time %u\n",
1676 (int)info
->cbSize
, (int)info
->dwFlags
, info
->hwndTrack
, (int)info
->dwHoverTime
);
1678 if (info
->cbSize
!= sizeof(TRACKMOUSEEVENT
))
1680 WARN( "wrong size %u\n", (int)info
->cbSize
);
1681 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
1685 if (info
->dwFlags
& TME_QUERY
)
1687 *info
= tracking_info
.info
;
1688 info
->cbSize
= sizeof(TRACKMOUSEEVENT
);
1692 if (!is_window( info
->hwndTrack
))
1694 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
1698 hover_time
= (info
->dwFlags
& TME_HOVER
) ? info
->dwHoverTime
: HOVER_DEFAULT
;
1700 if (hover_time
== HOVER_DEFAULT
|| hover_time
== 0)
1701 NtUserSystemParametersInfo( SPI_GETMOUSEHOVERTIME
, 0, &hover_time
, 0 );
1703 get_cursor_pos( &pos
);
1704 hwnd
= window_from_point( info
->hwndTrack
, pos
, &hittest
);
1705 TRACE( "point %s hwnd %p hittest %d\n", wine_dbgstr_point(&pos
), hwnd
, hittest
);
1707 if (info
->dwFlags
& ~(TME_CANCEL
| TME_HOVER
| TME_LEAVE
| TME_NONCLIENT
))
1708 FIXME( "ignoring flags %#x\n", (int)info
->dwFlags
& ~(TME_CANCEL
| TME_HOVER
| TME_LEAVE
| TME_NONCLIENT
) );
1710 if (info
->dwFlags
& TME_CANCEL
)
1712 if (tracking_info
.info
.hwndTrack
== info
->hwndTrack
)
1714 tracking_info
.info
.dwFlags
&= ~(info
->dwFlags
& ~TME_CANCEL
);
1716 /* if we aren't tracking on hover or leave remove this entry */
1717 if (!(tracking_info
.info
.dwFlags
& (TME_HOVER
| TME_LEAVE
)))
1719 kill_system_timer( tracking_info
.info
.hwndTrack
, SYSTEM_TIMER_TRACK_MOUSE
);
1720 tracking_info
.info
.hwndTrack
= 0;
1721 tracking_info
.info
.dwFlags
= 0;
1722 tracking_info
.info
.dwHoverTime
= 0;
1728 /* In our implementation, it's possible that another window will receive
1729 * WM_MOUSEMOVE and call TrackMouseEvent before TrackMouseEventProc is
1730 * called. In such a situation, post the WM_MOUSELEAVE now. */
1731 if ((tracking_info
.info
.dwFlags
& TME_LEAVE
) && tracking_info
.info
.hwndTrack
!= NULL
)
1732 check_mouse_leave(hwnd
, hittest
);
1734 kill_system_timer( tracking_info
.info
.hwndTrack
, SYSTEM_TIMER_TRACK_MOUSE
);
1735 tracking_info
.info
.hwndTrack
= 0;
1736 tracking_info
.info
.dwFlags
= 0;
1737 tracking_info
.info
.dwHoverTime
= 0;
1739 if (info
->hwndTrack
== hwnd
)
1741 /* Adding new mouse event to the tracking list */
1742 tracking_info
.info
= *info
;
1743 tracking_info
.info
.dwHoverTime
= hover_time
;
1745 /* Initialize HoverInfo variables even if not hover tracking */
1746 tracking_info
.pos
= pos
;
1748 NtUserSetSystemTimer( tracking_info
.info
.hwndTrack
, SYSTEM_TIMER_TRACK_MOUSE
, hover_time
);
1755 /**********************************************************************
1756 * set_capture_window
1758 BOOL
set_capture_window( HWND hwnd
, UINT gui_flags
, HWND
*prev_ret
)
1764 if (gui_flags
& GUI_INMENUMODE
) flags
|= CAPTURE_MENU
;
1765 if (gui_flags
& GUI_INMOVESIZE
) flags
|= CAPTURE_MOVESIZE
;
1767 SERVER_START_REQ( set_capture_window
)
1769 req
->handle
= wine_server_user_handle( hwnd
);
1771 if ((ret
= !wine_server_call_err( req
)))
1773 previous
= wine_server_ptr_handle( reply
->previous
);
1774 hwnd
= wine_server_ptr_handle( reply
->full_handle
);
1781 user_driver
->pSetCapture( hwnd
, gui_flags
);
1784 send_message( previous
, WM_CAPTURECHANGED
, 0, (LPARAM
)hwnd
);
1786 if (prev_ret
) *prev_ret
= previous
;
1791 /**********************************************************************
1792 * NtUserSetCapture (win32u.@)
1794 HWND WINAPI
NtUserSetCapture( HWND hwnd
)
1798 set_capture_window( hwnd
, 0, &previous
);
1802 /**********************************************************************
1805 BOOL
release_capture(void)
1807 HWND previous
= NULL
;
1810 ret
= set_capture_window( 0, 0, &previous
);
1812 /* Somebody may have missed some mouse movements */
1813 if (ret
&& previous
)
1815 INPUT input
= { .type
= INPUT_MOUSE
};
1816 input
.mi
.dwFlags
= MOUSEEVENTF_MOVE
;
1817 NtUserSendInput( 1, &input
, sizeof(input
) );
1823 /*****************************************************************
1826 * Change the focus window, sending the WM_SETFOCUS and WM_KILLFOCUS messages
1828 static HWND
set_focus_window( HWND hwnd
)
1830 HWND previous
= 0, ime_hwnd
;
1833 SERVER_START_REQ( set_focus_window
)
1835 req
->handle
= wine_server_user_handle( hwnd
);
1836 if ((ret
= !wine_server_call_err( req
)))
1837 previous
= wine_server_ptr_handle( reply
->previous
);
1841 if (previous
== hwnd
) return previous
;
1845 send_message( previous
, WM_KILLFOCUS
, (WPARAM
)hwnd
, 0 );
1847 ime_hwnd
= get_default_ime_window( previous
);
1849 send_message( ime_hwnd
, WM_IME_INTERNAL
, IME_INTERNAL_DEACTIVATE
,
1850 HandleToUlong(previous
) );
1852 if (hwnd
!= get_focus()) return previous
; /* changed by the message */
1854 if (is_window(hwnd
))
1856 user_driver
->pSetFocus(hwnd
);
1858 ime_hwnd
= get_default_ime_window( hwnd
);
1860 send_message( ime_hwnd
, WM_IME_INTERNAL
, IME_INTERNAL_ACTIVATE
,
1861 HandleToUlong(hwnd
) );
1863 NtUserNotifyWinEvent( EVENT_OBJECT_FOCUS
, hwnd
, OBJID_CLIENT
, 0 );
1865 send_message( hwnd
, WM_SETFOCUS
, (WPARAM
)previous
, 0 );
1870 /*******************************************************************
1873 static BOOL
set_active_window( HWND hwnd
, HWND
*prev
, BOOL mouse
, BOOL focus
)
1875 HWND previous
= get_active_window();
1877 DWORD old_thread
, new_thread
;
1878 CBTACTIVATESTRUCT cbt
;
1880 if (previous
== hwnd
)
1882 if (prev
) *prev
= hwnd
;
1886 /* call CBT hook chain */
1888 cbt
.hWndActive
= previous
;
1889 if (call_hooks( WH_CBT
, HCBT_ACTIVATE
, (WPARAM
)hwnd
, (LPARAM
)&cbt
, sizeof(cbt
) )) return FALSE
;
1891 if (is_window( previous
))
1893 send_message( previous
, WM_NCACTIVATE
, FALSE
, (LPARAM
)hwnd
);
1894 send_message( previous
, WM_ACTIVATE
,
1895 MAKEWPARAM( WA_INACTIVE
, is_iconic(previous
) ), (LPARAM
)hwnd
);
1898 SERVER_START_REQ( set_active_window
)
1900 req
->handle
= wine_server_user_handle( hwnd
);
1901 if ((ret
= !wine_server_call_err( req
)))
1902 previous
= wine_server_ptr_handle( reply
->previous
);
1905 if (!ret
) return FALSE
;
1906 if (prev
) *prev
= previous
;
1907 if (previous
== hwnd
) goto done
;
1911 NtUserNotifyWinEvent( EVENT_SYSTEM_FOREGROUND
, hwnd
, 0, 0 );
1913 /* send palette messages */
1914 if (send_message( hwnd
, WM_QUERYNEWPALETTE
, 0, 0 ))
1915 send_message_timeout( HWND_BROADCAST
, WM_PALETTEISCHANGING
, (WPARAM
)hwnd
, 0,
1916 SMTO_ABORTIFHUNG
, 2000, FALSE
);
1917 if (!is_window(hwnd
)) return FALSE
;
1920 old_thread
= previous
? get_window_thread( previous
, NULL
) : 0;
1921 new_thread
= hwnd
? get_window_thread( hwnd
, NULL
) : 0;
1923 if (old_thread
!= new_thread
)
1927 if ((list
= list_window_children( NULL
, get_desktop_window(), NULL
, 0 )))
1931 for (phwnd
= list
; *phwnd
; phwnd
++)
1933 if (get_window_thread( *phwnd
, NULL
) == old_thread
)
1934 send_message( *phwnd
, WM_ACTIVATEAPP
, 0, new_thread
);
1939 for (phwnd
= list
; *phwnd
; phwnd
++)
1941 if (get_window_thread( *phwnd
, NULL
) == new_thread
)
1942 send_message( *phwnd
, WM_ACTIVATEAPP
, 1, old_thread
);
1949 if (is_window(hwnd
))
1951 send_message( hwnd
, WM_NCACTIVATE
, hwnd
== NtUserGetForegroundWindow(), (LPARAM
)previous
);
1952 send_message( hwnd
, WM_ACTIVATE
,
1953 MAKEWPARAM( mouse
? WA_CLICKACTIVE
: WA_ACTIVE
, is_iconic(hwnd
) ),
1955 if (NtUserGetAncestor( hwnd
, GA_PARENT
) == get_desktop_window())
1956 NtUserPostMessage( get_desktop_window(), WM_PARENTNOTIFY
, WM_NCACTIVATE
, (LPARAM
)hwnd
);
1959 /* now change focus if necessary */
1964 info
.cbSize
= sizeof(info
);
1965 NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info
);
1966 /* Do not change focus if the window is no more active */
1967 if (hwnd
== info
.hwndActive
)
1969 if (!info
.hwndFocus
|| !hwnd
|| NtUserGetAncestor( info
.hwndFocus
, GA_ROOT
) != hwnd
)
1970 set_focus_window( hwnd
);
1975 if (hwnd
) clip_fullscreen_window( hwnd
, FALSE
);
1979 /**********************************************************************
1980 * NtUserSetActiveWindow (win32u.@)
1982 HWND WINAPI
NtUserSetActiveWindow( HWND hwnd
)
1986 TRACE( "%p\n", hwnd
);
1992 hwnd
= get_full_window_handle( hwnd
);
1993 if (!is_window( hwnd
))
1995 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
1999 style
= get_window_long( hwnd
, GWL_STYLE
);
2000 if ((style
& (WS_POPUP
|WS_CHILD
)) == WS_CHILD
)
2001 return get_active_window(); /* Windows doesn't seem to return an error here */
2004 if (!set_active_window( hwnd
, &prev
, FALSE
, TRUE
)) return 0;
2008 /*****************************************************************
2009 * NtUserSetFocus (win32u.@)
2011 HWND WINAPI
NtUserSetFocus( HWND hwnd
)
2013 HWND hwndTop
= hwnd
;
2014 HWND previous
= get_focus();
2016 TRACE( "%p prev %p\n", hwnd
, previous
);
2020 /* Check if we can set the focus to this window */
2021 hwnd
= get_full_window_handle( hwnd
);
2022 if (!is_window( hwnd
))
2024 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
2027 if (hwnd
== previous
) return previous
; /* nothing to do */
2031 LONG style
= get_window_long( hwndTop
, GWL_STYLE
);
2032 if (style
& (WS_MINIMIZE
| WS_DISABLED
)) return 0;
2033 if (!(style
& WS_CHILD
)) break;
2034 parent
= NtUserGetAncestor( hwndTop
, GA_PARENT
);
2035 if (!parent
|| parent
== get_desktop_window())
2037 if ((style
& (WS_POPUP
|WS_CHILD
)) == WS_CHILD
) return 0;
2040 if (parent
== get_hwnd_message_parent()) return 0;
2045 if (call_hooks( WH_CBT
, HCBT_SETFOCUS
, (WPARAM
)hwnd
, (LPARAM
)previous
, 0 )) return 0;
2047 /* activate hwndTop if needed. */
2048 if (hwndTop
!= get_active_window())
2050 if (!set_active_window( hwndTop
, NULL
, FALSE
, FALSE
)) return 0;
2051 if (!is_window( hwnd
)) return 0; /* Abort if window destroyed */
2053 /* Do not change focus if the window is no longer active */
2054 if (hwndTop
!= get_active_window()) return 0;
2057 else /* NULL hwnd passed in */
2059 if (!previous
) return 0; /* nothing to do */
2060 if (call_hooks( WH_CBT
, HCBT_SETFOCUS
, 0, (LPARAM
)previous
, 0 )) return 0;
2063 /* change focus and send messages */
2064 return set_focus_window( hwnd
);
2067 /*******************************************************************
2068 * set_foreground_window
2070 BOOL
set_foreground_window( HWND hwnd
, BOOL mouse
)
2072 BOOL ret
, send_msg_old
= FALSE
, send_msg_new
= FALSE
;
2075 if (mouse
) hwnd
= get_full_window_handle( hwnd
);
2077 SERVER_START_REQ( set_foreground_window
)
2079 req
->handle
= wine_server_user_handle( hwnd
);
2080 if ((ret
= !wine_server_call_err( req
)))
2082 previous
= wine_server_ptr_handle( reply
->previous
);
2083 send_msg_old
= reply
->send_msg_old
;
2084 send_msg_new
= reply
->send_msg_new
;
2089 if (ret
&& previous
!= hwnd
)
2091 if (send_msg_old
) /* old window belongs to other thread */
2092 NtUserMessageCall( previous
, WM_WINE_SETACTIVEWINDOW
, 0, 0,
2093 0, NtUserSendNotifyMessage
, FALSE
);
2094 else if (send_msg_new
) /* old window belongs to us but new one to other thread */
2095 ret
= set_active_window( 0, NULL
, mouse
, TRUE
);
2097 if (send_msg_new
) /* new window belongs to other thread */
2098 NtUserMessageCall( hwnd
, WM_WINE_SETACTIVEWINDOW
, (WPARAM
)hwnd
, 0,
2099 0, NtUserSendNotifyMessage
, FALSE
);
2100 else /* new window belongs to us */
2101 ret
= set_active_window( hwnd
, NULL
, mouse
, TRUE
);
2109 unsigned int timeout
;
2112 static void display_caret( HWND hwnd
, const RECT
*r
)
2116 /* do not use DCX_CACHE here, since coördinates are in logical units */
2117 if (!(dc
= NtUserGetDCEx( hwnd
, 0, DCX_USESTYLE
)))
2119 mem_dc
= NtGdiCreateCompatibleDC(dc
);
2122 HBITMAP prev_bitmap
;
2124 prev_bitmap
= NtGdiSelectBitmap( mem_dc
, caret
.bitmap
);
2125 NtGdiBitBlt( dc
, r
->left
, r
->top
, r
->right
-r
->left
, r
->bottom
-r
->top
, mem_dc
, 0, 0, SRCINVERT
, 0, 0 );
2126 NtGdiSelectBitmap( mem_dc
, prev_bitmap
);
2127 NtGdiDeleteObjectApp( mem_dc
);
2129 NtUserReleaseDC( hwnd
, dc
);
2132 static unsigned int get_caret_registry_timeout(void)
2134 char value_buffer
[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[11 * sizeof(WCHAR
)])];
2135 KEY_VALUE_PARTIAL_INFORMATION
*value
= (void *)value_buffer
;
2136 unsigned int ret
= 500;
2139 if (!(key
= reg_open_hkcu_key( "Control Panel\\Desktop" )))
2142 if (query_reg_ascii_value( key
, "CursorBlinkRate", value
, sizeof(value_buffer
) ))
2143 ret
= wcstoul( (WCHAR
*)value
->Data
, NULL
, 10 );
2148 /*****************************************************************
2149 * NtUserCreateCaret (win32u.@)
2151 BOOL WINAPI
NtUserCreateCaret( HWND hwnd
, HBITMAP bitmap
, int width
, int height
)
2153 HBITMAP caret_bitmap
= 0;
2160 TRACE( "hwnd %p, bitmap %p, width %d, height %d\n", hwnd
, bitmap
, width
, height
);
2162 if (!hwnd
) return FALSE
;
2164 if (bitmap
&& bitmap
!= (HBITMAP
)1)
2168 if (!NtGdiExtGetObjectW( bitmap
, sizeof(bitmap_data
), &bitmap_data
)) return FALSE
;
2169 width
= bitmap_data
.bmWidth
;
2170 height
= bitmap_data
.bmHeight
;
2171 caret_bitmap
= NtGdiCreateBitmap( bitmap_data
.bmWidth
, bitmap_data
.bmHeight
,
2172 bitmap_data
.bmPlanes
, bitmap_data
.bmBitsPixel
, NULL
);
2175 size_t size
= bitmap_data
.bmWidthBytes
* bitmap_data
.bmHeight
;
2176 BYTE
*bits
= malloc( size
);
2178 NtGdiGetBitmapBits( bitmap
, size
, bits
);
2179 NtGdiSetBitmapBits( caret_bitmap
, size
, bits
);
2187 if (!width
) width
= get_system_metrics( SM_CXBORDER
);
2188 if (!height
) height
= get_system_metrics( SM_CYBORDER
);
2190 /* create the uniform bitmap on the fly */
2191 dc
= NtUserGetDCEx( hwnd
, 0, DCX_USESTYLE
);
2194 HDC mem_dc
= NtGdiCreateCompatibleDC( dc
);
2197 if ((caret_bitmap
= NtGdiCreateCompatibleBitmap( mem_dc
, width
, height
)))
2199 HBITMAP prev_bitmap
= NtGdiSelectBitmap( mem_dc
, caret_bitmap
);
2200 SetRect( &r
, 0, 0, width
, height
);
2201 fill_rect( mem_dc
, &r
, GetStockObject( bitmap
? GRAY_BRUSH
: WHITE_BRUSH
));
2202 NtGdiSelectBitmap( mem_dc
, prev_bitmap
);
2204 NtGdiDeleteObjectApp( mem_dc
);
2206 NtUserReleaseDC( hwnd
, dc
);
2209 if (!caret_bitmap
) return FALSE
;
2211 SERVER_START_REQ( set_caret_window
)
2213 req
->handle
= wine_server_user_handle( hwnd
);
2215 req
->height
= height
;
2216 if ((ret
= !wine_server_call_err( req
)))
2218 prev
= wine_server_ptr_handle( reply
->previous
);
2219 r
= wine_server_get_rect( reply
->old_rect
);
2220 old_state
= reply
->old_state
;
2221 hidden
= reply
->old_hide
;
2225 if (!ret
) return FALSE
;
2227 if (prev
&& !hidden
) /* hide the previous one */
2229 /* FIXME: won't work if prev belongs to a different process */
2230 kill_system_timer( prev
, SYSTEM_TIMER_CARET
);
2231 if (old_state
) display_caret( prev
, &r
);
2234 if (caret
.bitmap
) NtGdiDeleteObjectApp( caret
.bitmap
);
2235 caret
.bitmap
= caret_bitmap
;
2236 caret
.timeout
= get_caret_registry_timeout();
2240 /*******************************************************************
2243 BOOL
destroy_caret(void)
2251 SERVER_START_REQ( set_caret_window
)
2256 if ((ret
= !wine_server_call_err( req
)))
2258 prev
= wine_server_ptr_handle( reply
->previous
);
2259 r
= wine_server_get_rect( reply
->old_rect
);
2260 old_state
= reply
->old_state
;
2261 hidden
= reply
->old_hide
;
2266 if (ret
&& prev
&& !hidden
)
2268 /* FIXME: won't work if prev belongs to a different process */
2269 kill_system_timer( prev
, SYSTEM_TIMER_CARET
);
2270 if (old_state
) display_caret( prev
, &r
);
2272 if (caret
.bitmap
) NtGdiDeleteObjectApp( caret
.bitmap
);
2277 /*****************************************************************
2278 * NtUserGetCaretBlinkTime (win32u.@)
2280 UINT WINAPI
NtUserGetCaretBlinkTime(void)
2282 return caret
.timeout
;
2285 /*******************************************************************
2286 * set_caret_blink_time
2288 BOOL
set_caret_blink_time( unsigned int time
)
2290 TRACE( "time %u\n", time
);
2292 caret
.timeout
= time
;
2293 /* FIXME: update the timer */
2297 /*****************************************************************
2298 * NtUserGetCaretPos (win32u.@)
2300 BOOL WINAPI
NtUserGetCaretPos( POINT
*pt
)
2304 SERVER_START_REQ( set_caret_info
)
2306 req
->flags
= 0; /* don't set anything */
2312 if ((ret
= !wine_server_call_err( req
)))
2314 pt
->x
= reply
->old_rect
.left
;
2315 pt
->y
= reply
->old_rect
.top
;
2322 /*******************************************************************
2325 BOOL
set_caret_pos( int x
, int y
)
2333 TRACE( "(%d, %d)\n", x
, y
);
2335 SERVER_START_REQ( set_caret_info
)
2337 req
->flags
= SET_CARET_POS
|SET_CARET_STATE
;
2342 req
->state
= CARET_STATE_ON_IF_MOVED
;
2343 if ((ret
= !wine_server_call_err( req
)))
2345 hwnd
= wine_server_ptr_handle( reply
->full_handle
);
2346 r
= wine_server_get_rect( reply
->old_rect
);
2347 old_state
= reply
->old_state
;
2348 hidden
= reply
->old_hide
;
2352 if (ret
&& !hidden
&& (x
!= r
.left
|| y
!= r
.top
))
2354 if (old_state
) display_caret( hwnd
, &r
);
2355 r
.right
+= x
- r
.left
;
2356 r
.bottom
+= y
- r
.top
;
2359 display_caret( hwnd
, &r
);
2360 NtUserSetSystemTimer( hwnd
, SYSTEM_TIMER_CARET
, caret
.timeout
);
2365 /*****************************************************************
2366 * NtUserShowCaret (win32u.@)
2368 BOOL WINAPI
NtUserShowCaret( HWND hwnd
)
2374 SERVER_START_REQ( set_caret_info
)
2376 req
->flags
= SET_CARET_HIDE
| SET_CARET_STATE
;
2377 req
->handle
= wine_server_user_handle( hwnd
);
2381 req
->state
= CARET_STATE_ON
;
2382 if ((ret
= !wine_server_call_err( req
)))
2384 hwnd
= wine_server_ptr_handle( reply
->full_handle
);
2385 r
= wine_server_get_rect( reply
->old_rect
);
2386 hidden
= reply
->old_hide
;
2391 if (ret
&& hidden
== 1) /* hidden was 1 so it's now 0 */
2393 display_caret( hwnd
, &r
);
2394 NtUserSetSystemTimer( hwnd
, SYSTEM_TIMER_CARET
, caret
.timeout
);
2399 /*****************************************************************
2400 * NtUserHideCaret (win32u.@)
2402 BOOL WINAPI
NtUserHideCaret( HWND hwnd
)
2409 SERVER_START_REQ( set_caret_info
)
2411 req
->flags
= SET_CARET_HIDE
| SET_CARET_STATE
;
2412 req
->handle
= wine_server_user_handle( hwnd
);
2416 req
->state
= CARET_STATE_OFF
;
2417 if ((ret
= !wine_server_call_err( req
)))
2419 hwnd
= wine_server_ptr_handle( reply
->full_handle
);
2420 r
= wine_server_get_rect( reply
->old_rect
);
2421 old_state
= reply
->old_state
;
2422 hidden
= reply
->old_hide
;
2429 if (old_state
) display_caret( hwnd
, &r
);
2430 kill_system_timer( hwnd
, SYSTEM_TIMER_CARET
);
2435 void toggle_caret( HWND hwnd
)
2441 SERVER_START_REQ( set_caret_info
)
2443 req
->flags
= SET_CARET_STATE
;
2444 req
->handle
= wine_server_user_handle( hwnd
);
2448 req
->state
= CARET_STATE_TOGGLE
;
2449 if ((ret
= !wine_server_call( req
)))
2451 hwnd
= wine_server_ptr_handle( reply
->full_handle
);
2452 r
= wine_server_get_rect( reply
->old_rect
);
2453 hidden
= reply
->old_hide
;
2458 if (ret
&& !hidden
) display_caret( hwnd
, &r
);
2462 /**********************************************************************
2463 * NtUserEnableMouseInPointer (win32u.@)
2465 BOOL WINAPI
NtUserEnableMouseInPointer( BOOL enable
)
2467 FIXME( "enable %u stub!\n", enable
);
2468 RtlSetLastWin32Error( ERROR_CALL_NOT_IMPLEMENTED
);
2472 /**********************************************************************
2473 * NtUserIsMouseInPointerEnabled (win32u.@)
2475 BOOL WINAPI
NtUserIsMouseInPointerEnabled(void)
2478 RtlSetLastWin32Error( ERROR_CALL_NOT_IMPLEMENTED
);
2482 static BOOL
is_captured_by_system(void)
2485 info
.cbSize
= sizeof(info
);
2486 return NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info
) && info
.hwndCapture
&& (info
.flags
& (GUI_INMOVESIZE
| GUI_INMENUMODE
));
2489 /***********************************************************************
2490 * clip_fullscreen_window
2492 * Turn on clipping if the active window is fullscreen.
2494 BOOL
clip_fullscreen_window( HWND hwnd
, BOOL reset
)
2496 struct user_thread_info
*thread_info
= get_user_thread_info();
2497 MONITORINFO monitor_info
= {.cbSize
= sizeof(MONITORINFO
)};
2504 if (hwnd
== NtUserGetDesktopWindow()) return FALSE
;
2505 if (hwnd
!= NtUserGetForegroundWindow()) return FALSE
;
2507 style
= NtUserGetWindowLongW( hwnd
, GWL_STYLE
);
2508 if (!(style
& WS_VISIBLE
)) return FALSE
;
2509 if ((style
& (WS_POPUP
| WS_CHILD
)) == WS_CHILD
) return FALSE
;
2510 /* maximized windows don't count as full screen */
2511 if ((style
& WS_MAXIMIZE
) && (style
& WS_CAPTION
) == WS_CAPTION
) return FALSE
;
2513 dpi
= get_dpi_for_window( hwnd
);
2514 if (!NtUserGetWindowRect( hwnd
, &rect
, dpi
)) return FALSE
;
2515 if (!NtUserIsWindowRectFullScreen( &rect
, dpi
)) return FALSE
;
2516 if (is_captured_by_system()) return FALSE
;
2517 if (NtGetTickCount() - thread_info
->clipping_reset
< 1000) return FALSE
;
2518 if (!reset
&& clipping_cursor
&& thread_info
->clipping_cursor
) return FALSE
; /* already clipping */
2520 if (!(monitor
= NtUserMonitorFromWindow( hwnd
, MONITOR_DEFAULTTONEAREST
))) return FALSE
;
2521 if (!get_monitor_info( monitor
, &monitor_info
, 0 )) return FALSE
;
2522 if (!grab_fullscreen
)
2524 RECT virtual_rect
= NtUserGetVirtualScreenRect();
2525 if (!EqualRect( &monitor_info
.rcMonitor
, &virtual_rect
)) return FALSE
;
2526 if (is_virtual_desktop()) return FALSE
;
2529 TRACE( "win %p clipping fullscreen\n", hwnd
);
2531 SERVER_START_REQ( set_cursor
)
2533 req
->flags
= SET_CURSOR_CLIP
| SET_CURSOR_FSCLIP
;
2534 req
->clip
= wine_server_rectangle( monitor_info
.rcMonitor
);
2535 ret
= !wine_server_call( req
);
2542 /**********************************************************************
2543 * NtUserGetPointerInfoList (win32u.@)
2545 BOOL WINAPI
NtUserGetPointerInfoList( UINT32 id
, POINTER_INPUT_TYPE type
, UINT_PTR unk0
, UINT_PTR unk1
, SIZE_T size
,
2546 UINT32
*entry_count
, UINT32
*pointer_count
, void *pointer_info
)
2548 FIXME( "id %#x, type %#x, unk0 %#zx, unk1 %#zx, size %#zx, entry_count %p, pointer_count %p, pointer_info %p stub!\n",
2549 id
, (int)type
, (size_t)unk0
, (size_t)unk1
, (size_t)size
, entry_count
, pointer_count
, pointer_info
);
2550 RtlSetLastWin32Error( ERROR_CALL_NOT_IMPLEMENTED
);
2554 BOOL
get_clip_cursor( RECT
*rect
, UINT dpi
)
2556 struct object_lock lock
= OBJECT_LOCK_INIT
;
2557 const desktop_shm_t
*desktop_shm
;
2560 if (!rect
) return FALSE
;
2562 while ((status
= get_shared_desktop( &lock
, &desktop_shm
)) == STATUS_PENDING
)
2563 *rect
= wine_server_get_rect( desktop_shm
->cursor
.clip
);
2567 HMONITOR monitor
= monitor_from_rect( rect
, MONITOR_DEFAULTTOPRIMARY
, 0 );
2568 *rect
= map_dpi_rect( *rect
, get_monitor_dpi( monitor
), dpi
);
2573 BOOL
process_wine_clipcursor( HWND hwnd
, UINT flags
, BOOL reset
)
2575 struct user_thread_info
*thread_info
= get_user_thread_info();
2576 RECT rect
, virtual_rect
= NtUserGetVirtualScreenRect();
2577 BOOL was_clipping
, empty
= !!(flags
& SET_CURSOR_NOCLIP
);
2579 TRACE( "hwnd %p, flags %#x, reset %u\n", hwnd
, flags
, reset
);
2581 if ((was_clipping
= thread_info
->clipping_cursor
)) InterlockedDecrement( &clipping_cursor
);
2582 thread_info
->clipping_cursor
= FALSE
;
2586 thread_info
->clipping_reset
= NtGetTickCount();
2587 return user_driver
->pClipCursor( NULL
, TRUE
);
2590 if (!grab_pointer
) return TRUE
;
2592 /* we are clipping if the clip rectangle is smaller than the screen */
2593 get_clip_cursor( &rect
, 0 );
2594 intersect_rect( &rect
, &rect
, &virtual_rect
);
2595 if (EqualRect( &rect
, &virtual_rect
)) empty
= TRUE
;
2596 if (empty
&& !(flags
& SET_CURSOR_FSCLIP
))
2598 /* if currently clipping, check if we should switch to fullscreen clipping */
2599 if (was_clipping
&& clip_fullscreen_window( hwnd
, TRUE
)) return TRUE
;
2600 return user_driver
->pClipCursor( NULL
, FALSE
);
2603 if (!user_driver
->pClipCursor( &rect
, FALSE
)) return FALSE
;
2604 InterlockedIncrement( &clipping_cursor
);
2605 thread_info
->clipping_cursor
= TRUE
;
2609 /***********************************************************************
2610 * NtUserClipCursor (win32u.@)
2612 BOOL WINAPI
NtUserClipCursor( const RECT
*rect
)
2618 TRACE( "Clipping to %s\n", wine_dbgstr_rect(rect
) );
2622 if (rect
->left
> rect
->right
|| rect
->top
> rect
->bottom
) return FALSE
;
2623 if ((dpi
= get_thread_dpi()))
2625 HMONITOR monitor
= monitor_from_rect( rect
, MONITOR_DEFAULTTOPRIMARY
, dpi
);
2626 new_rect
= map_dpi_rect( *rect
, dpi
, get_monitor_dpi( monitor
));
2631 SERVER_START_REQ( set_cursor
)
2635 req
->flags
= SET_CURSOR_CLIP
;
2636 req
->clip
= wine_server_rectangle( *rect
);
2638 else req
->flags
= SET_CURSOR_NOCLIP
;
2640 ret
= !wine_server_call( req
);