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
),
408 LONG global_key_state_counter
= 0;
411 static void kbd_tables_init_vsc2vk( const KBDTABLES
*tables
, BYTE vsc2vk
[0x300] )
416 memset( vsc2vk
, 0, 0x300 );
418 for (vsc
= 0; tables
->pusVSCtoVK
&& vsc
<= tables
->bMaxVSCtoVK
; ++vsc
)
420 if (tables
->pusVSCtoVK
[vsc
] == VK__none_
) continue;
421 vsc2vk
[vsc
] = (BYTE
)tables
->pusVSCtoVK
[vsc
];
423 for (entry
= tables
->pVSCtoVK_E0
; entry
&& entry
->Vsc
; entry
++)
425 if (entry
->Vk
== VK__none_
) continue;
426 vsc2vk
[entry
->Vsc
+ 0x100] = (BYTE
)entry
->Vk
;
428 for (entry
= tables
->pVSCtoVK_E1
; entry
&& entry
->Vsc
; entry
++)
430 if (entry
->Vk
== VK__none_
) continue;
431 vsc2vk
[entry
->Vsc
+ 0x200] = (BYTE
)entry
->Vk
;
435 #define NEXT_ENTRY(t, e) ((void *)&(e)->wch[(t)->nModifications])
437 static void kbd_tables_init_vk2char( const KBDTABLES
*tables
, BYTE vk2char
[0x100] )
439 const VK_TO_WCHAR_TABLE
*table
;
440 const VK_TO_WCHARS1
*entry
;
442 memset( vk2char
, 0, 0x100 );
444 for (table
= tables
->pVkToWcharTable
; table
->pVkToWchars
; table
++)
446 for (entry
= table
->pVkToWchars
; entry
->VirtualKey
; entry
= NEXT_ENTRY(table
, entry
))
448 if (entry
->VirtualKey
& ~0xff) continue;
449 vk2char
[entry
->VirtualKey
] = entry
->wch
[0];
454 static UINT
kbd_tables_get_mod_bits( const KBDTABLES
*tables
, UINT mod
)
456 const MODIFIERS
*mods
= tables
->pCharModifiers
;
459 for (bits
= 0; bits
<= mods
->wMaxModBits
; ++bits
)
460 if (mods
->ModNumber
[bits
] == mod
) return bits
;
465 static UINT
kbd_tables_get_mod_num( const KBDTABLES
*tables
, const BYTE
*state
, BOOL caps
)
467 const MODIFIERS
*mods
= tables
->pCharModifiers
;
468 const VK_TO_BIT
*entry
;
471 for (entry
= mods
->pVkToBit
; entry
->Vk
; ++entry
)
472 if (state
[entry
->Vk
] & 0x80) bits
|= entry
->ModBits
;
473 if (caps
) bits
|= KBDSHIFT
;
475 if (bits
> mods
->wMaxModBits
) return -1;
476 return mods
->ModNumber
[bits
];
479 static WORD
kbd_tables_wchar_to_vkey( const KBDTABLES
*tables
, WCHAR wch
)
481 const VK_TO_WCHAR_TABLE
*table
;
482 const VK_TO_WCHARS1
*entry
;
486 if (wch
== '\x001b') return VK_ESCAPE
;
488 for (table
= tables
->pVkToWcharTable
; table
->pVkToWchars
; table
++)
490 for (entry
= table
->pVkToWchars
; entry
->VirtualKey
; entry
= NEXT_ENTRY(table
, entry
))
492 for (mod
= 0; mod
< table
->nModifications
; ++mod
)
494 if (entry
->wch
[mod
] == WCH_NONE
|| entry
->wch
[mod
] != wch
) continue;
495 bits
= kbd_tables_get_mod_bits( tables
, mod
);
496 return (bits
<< 8) | entry
->VirtualKey
;
501 if (wch
>= 0x0001 && wch
<= 0x001a) return (0x200) | ('A' + wch
- 1); /* CTRL + A-Z */
502 return wch
>= 0x0080 ? -1 : 0;
505 static WCHAR
kbd_tables_vkey_to_wchar( const KBDTABLES
*tables
, UINT vkey
, const BYTE
*state
)
507 UINT mod
, caps_mod
, alt
, ctrl
, caps
;
508 const VK_TO_WCHAR_TABLE
*table
;
509 const VK_TO_WCHARS1
*entry
;
511 alt
= state
[VK_MENU
] & 0x80;
512 ctrl
= state
[VK_CONTROL
] & 0x80;
513 caps
= state
[VK_CAPITAL
] & 1;
515 if (ctrl
&& alt
) return WCH_NONE
;
516 if (!ctrl
&& vkey
== VK_ESCAPE
) return VK_ESCAPE
;
518 mod
= caps_mod
= kbd_tables_get_mod_num( tables
, state
, FALSE
);
519 if (caps
) caps_mod
= kbd_tables_get_mod_num( tables
, state
, TRUE
);
521 for (table
= tables
->pVkToWcharTable
; table
->pVkToWchars
; table
++)
523 if (table
->nModifications
<= mod
) continue;
524 for (entry
= table
->pVkToWchars
; entry
->VirtualKey
; entry
= NEXT_ENTRY(table
, entry
))
526 if (entry
->VirtualKey
!= vkey
) continue;
527 if ((entry
->Attributes
& CAPLOK
) && table
->nModifications
> caps_mod
) return entry
->wch
[caps_mod
];
528 return entry
->wch
[mod
];
532 if (ctrl
&& vkey
>= 'A' && vkey
<= 'Z') return vkey
- 'A' + 1;
538 /*******************************************************************
539 * NtUserGetForegroundWindow (win32u.@)
541 HWND WINAPI
NtUserGetForegroundWindow(void)
545 SERVER_START_REQ( get_thread_input
)
548 if (!wine_server_call_err( req
)) ret
= wine_server_ptr_handle( reply
->foreground
);
554 /* see GetActiveWindow */
555 HWND
get_active_window(void)
558 info
.cbSize
= sizeof(info
);
559 return NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info
) ? info
.hwndActive
: 0;
563 HWND
get_capture(void)
566 info
.cbSize
= sizeof(info
);
567 return NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info
) ? info
.hwndCapture
: 0;
574 info
.cbSize
= sizeof(info
);
575 return NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info
) ? info
.hwndFocus
: 0;
578 /**********************************************************************
579 * NtUserAttachThreadInput (win32u.@)
581 BOOL WINAPI
NtUserAttachThreadInput( DWORD from
, DWORD to
, BOOL attach
)
585 SERVER_START_REQ( attach_thread_input
)
587 req
->tid_from
= from
;
589 req
->attach
= attach
;
590 ret
= !wine_server_call_err( req
);
596 /***********************************************************************
597 * __wine_send_input (win32u.@)
599 * Internal SendInput function to allow the graphics driver to inject real events.
601 BOOL WINAPI
__wine_send_input( HWND hwnd
, const INPUT
*input
, const RAWINPUT
*rawinput
)
603 return set_ntstatus( send_hardware_message( hwnd
, input
, rawinput
, 0 ));
606 /***********************************************************************
607 * update_mouse_coords
609 * Helper for NtUserSendInput.
611 static void update_mouse_coords( INPUT
*input
)
613 if (!(input
->mi
.dwFlags
& MOUSEEVENTF_MOVE
)) return;
615 if (input
->mi
.dwFlags
& MOUSEEVENTF_ABSOLUTE
)
619 if (input
->mi
.dwFlags
& MOUSEEVENTF_VIRTUALDESK
)
620 rc
= get_virtual_screen_rect( 0 );
622 rc
= get_primary_monitor_rect( 0 );
624 input
->mi
.dx
= rc
.left
+ ((input
->mi
.dx
* (rc
.right
- rc
.left
)) >> 16);
625 input
->mi
.dy
= rc
.top
+ ((input
->mi
.dy
* (rc
.bottom
- rc
.top
)) >> 16);
631 /* dx and dy can be negative numbers for relative movements */
632 NtUserSystemParametersInfo( SPI_GETMOUSE
, 0, accel
, 0 );
634 if (!accel
[2]) return;
636 if (abs( input
->mi
.dx
) > accel
[0])
639 if (abs( input
->mi
.dx
) > accel
[1] && accel
[2] == 2) input
->mi
.dx
*= 2;
641 if (abs(input
->mi
.dy
) > accel
[0])
644 if (abs( input
->mi
.dy
) > accel
[1] && accel
[2] == 2) input
->mi
.dy
*= 2;
649 /***********************************************************************
650 * NtUserSendInput (win32u.@)
652 UINT WINAPI
NtUserSendInput( UINT count
, INPUT
*inputs
, int size
)
655 NTSTATUS status
= STATUS_SUCCESS
;
657 if (size
!= sizeof(INPUT
))
659 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
665 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
671 RtlSetLastWin32Error( ERROR_NOACCESS
);
675 for (i
= 0; i
< count
; i
++)
677 INPUT input
= inputs
[i
];
681 /* we need to update the coordinates to what the server expects */
682 update_mouse_coords( &input
);
685 status
= send_hardware_message( 0, &input
, NULL
, SEND_HWMSG_INJECTED
);
688 RtlSetLastWin32Error( ERROR_CALL_NOT_IMPLEMENTED
);
694 RtlSetLastWin32Error( RtlNtStatusToDosError(status
) );
702 /***********************************************************************
703 * NtUserSetCursorPos (win32u.@)
705 BOOL WINAPI
NtUserSetCursorPos( INT x
, INT y
)
709 INT prev_x
, prev_y
, new_x
, new_y
;
712 if ((dpi
= get_thread_dpi()))
714 HMONITOR monitor
= monitor_from_point( pt
, MONITOR_DEFAULTTOPRIMARY
, get_thread_dpi() );
715 pt
= map_dpi_point( pt
, dpi
, get_monitor_dpi( monitor
));
718 SERVER_START_REQ( set_cursor
)
720 req
->flags
= SET_CURSOR_POS
;
723 if ((ret
= !wine_server_call( req
)))
725 prev_x
= reply
->prev_x
;
726 prev_y
= reply
->prev_y
;
727 new_x
= reply
->new_x
;
728 new_y
= reply
->new_y
;
732 if (ret
&& (prev_x
!= new_x
|| prev_y
!= new_y
)) user_driver
->pSetCursorPos( new_x
, new_y
);
736 /***********************************************************************
739 BOOL
get_cursor_pos( POINT
*pt
)
745 if (!pt
) return FALSE
;
747 SERVER_START_REQ( set_cursor
)
749 if ((ret
= !wine_server_call( req
)))
751 pt
->x
= reply
->new_x
;
752 pt
->y
= reply
->new_y
;
753 last_change
= reply
->last_change
;
758 /* query new position from graphics driver if we haven't updated recently */
759 if (ret
&& NtGetTickCount() - last_change
> 100) ret
= user_driver
->pGetCursorPos( pt
);
760 if (ret
&& (dpi
= get_thread_dpi()))
762 HMONITOR monitor
= monitor_from_point( *pt
, MONITOR_DEFAULTTOPRIMARY
, 0 );
763 *pt
= map_dpi_point( *pt
, get_monitor_dpi( monitor
), dpi
);
768 /***********************************************************************
769 * NtUserGetCursorInfo (win32u.@)
771 BOOL WINAPI
NtUserGetCursorInfo( CURSORINFO
*info
)
775 if (!info
) return FALSE
;
777 SERVER_START_REQ( get_thread_input
)
780 if ((ret
= !wine_server_call( req
)))
782 info
->hCursor
= wine_server_ptr_handle( reply
->cursor
);
783 info
->flags
= reply
->show_count
>= 0 ? CURSOR_SHOWING
: 0;
787 get_cursor_pos( &info
->ptScreenPos
);
791 static void check_for_events( UINT flags
)
793 if (!user_driver
->pProcessEvents( flags
))
794 flush_window_surfaces( TRUE
);
797 /**********************************************************************
798 * GetAsyncKeyState (win32u.@)
800 SHORT WINAPI
NtUserGetAsyncKeyState( INT key
)
802 struct user_key_state_info
*key_state_info
= get_user_thread_info()->key_state
;
803 INT counter
= global_key_state_counter
;
807 if (key
< 0 || key
>= 256) return 0;
809 check_for_events( QS_INPUT
);
811 if (key_state_info
&& !(key_state_info
->state
[key
] & 0xc0) &&
812 key_state_info
->counter
== counter
&& NtGetTickCount() - key_state_info
->time
< 50)
814 /* use cached value */
817 else if (!key_state_info
)
819 key_state_info
= calloc( 1, sizeof(*key_state_info
) );
820 get_user_thread_info()->key_state
= key_state_info
;
824 SERVER_START_REQ( get_key_state
)
830 prev_key_state
= key_state_info
->state
[key
];
831 wine_server_set_reply( req
, key_state_info
->state
, sizeof(key_state_info
->state
) );
833 if (!wine_server_call( req
))
835 if (reply
->state
& 0x40) ret
|= 0x0001;
836 if (reply
->state
& 0x80) ret
|= 0x8000;
839 /* force refreshing the key state cache - some multithreaded programs
840 * (like Adobe Photoshop CS5) expect that changes to the async key state
841 * are also immediately available in other threads. */
842 if (prev_key_state
!= key_state_info
->state
[key
])
843 counter
= InterlockedIncrement( &global_key_state_counter
);
845 key_state_info
->time
= NtGetTickCount();
846 key_state_info
->counter
= counter
;
855 /***********************************************************************
856 * NtUserGetQueueStatus (win32u.@)
858 DWORD WINAPI
NtUserGetQueueStatus( UINT flags
)
862 if (flags
& ~(QS_ALLINPUT
| QS_ALLPOSTMESSAGE
| QS_SMRESULT
))
864 RtlSetLastWin32Error( ERROR_INVALID_FLAGS
);
868 check_for_events( flags
);
870 SERVER_START_REQ( get_queue_status
)
872 req
->clear_bits
= flags
;
873 wine_server_call( req
);
874 ret
= MAKELONG( reply
->changed_bits
& flags
, reply
->wake_bits
& flags
);
880 /***********************************************************************
883 DWORD
get_input_state(void)
887 check_for_events( QS_INPUT
);
889 SERVER_START_REQ( get_queue_status
)
892 wine_server_call( req
);
893 ret
= reply
->wake_bits
& (QS_KEY
| QS_MOUSEBUTTON
);
899 /***********************************************************************
900 * get_locale_kbd_layout
902 static HKL
get_locale_kbd_layout(void)
909 * layout = main_key_tab[kbd_layout].lcid;
911 * Winword uses return value of GetKeyboardLayout as a codepage
912 * to translate ANSI keyboard messages to unicode. But we have
913 * a problem with it: for instance Polish keyboard layout is
914 * identical to the US one, and therefore instead of the Polish
915 * locale id we return the US one.
918 NtQueryDefaultLocale( TRUE
, &layout
);
921 * Microsoft Office expects this value to be something specific
922 * for Japanese and Korean Windows with an IME the value is 0xe001
923 * We should probably check to see if an IME exists and if so then
924 * set this word properly.
926 langid
= PRIMARYLANGID( LANGIDFROMLCID( layout
) );
927 if (langid
== LANG_CHINESE
|| langid
== LANG_JAPANESE
|| langid
== LANG_KOREAN
)
928 layout
= MAKELONG( layout
, 0xe001 ); /* IME */
930 layout
= MAKELONG( layout
, layout
);
932 return ULongToHandle( layout
);
935 /***********************************************************************
936 * NtUserGetKeyboardLayout (win32u.@)
938 * Device handle for keyboard layout defaulted to
939 * the language id. This is the way Windows default works.
941 HKL WINAPI
NtUserGetKeyboardLayout( DWORD thread_id
)
943 struct user_thread_info
*thread
= get_user_thread_info();
944 HKL layout
= thread
->kbd_layout
;
946 if (thread_id
&& thread_id
!= GetCurrentThreadId())
947 FIXME( "couldn't return keyboard layout for thread %04x\n", (int)thread_id
);
949 if (!layout
) return get_locale_kbd_layout();
953 /**********************************************************************
954 * NtUserGetKeyState (win32u.@)
956 * An application calls the GetKeyState function in response to a
957 * keyboard-input message. This function retrieves the state of the key
958 * at the time the input message was generated.
960 SHORT WINAPI
NtUserGetKeyState( INT vkey
)
964 SERVER_START_REQ( get_key_state
)
967 if (!wine_server_call( req
)) retval
= (signed char)(reply
->state
& 0x81);
970 TRACE("key (0x%x) -> %x\n", vkey
, retval
);
974 /**********************************************************************
975 * NtUserGetKeyboardState (win32u.@)
977 BOOL WINAPI
NtUserGetKeyboardState( BYTE
*state
)
982 TRACE("(%p)\n", state
);
984 memset( state
, 0, 256 );
985 SERVER_START_REQ( get_key_state
)
988 wine_server_set_reply( req
, state
, 256 );
989 ret
= !wine_server_call_err( req
);
990 for (i
= 0; i
< 256; i
++) state
[i
] &= 0x81;
996 /**********************************************************************
997 * NtUserSetKeyboardState (win32u.@)
999 BOOL WINAPI
NtUserSetKeyboardState( BYTE
*state
)
1003 SERVER_START_REQ( set_key_state
)
1005 wine_server_add_data( req
, state
, 256 );
1006 ret
= !wine_server_call_err( req
);
1012 /******************************************************************************
1013 * NtUserVkKeyScanEx (win32u.@)
1015 WORD WINAPI
NtUserVkKeyScanEx( WCHAR chr
, HKL layout
)
1017 const KBDTABLES
*kbd_tables
= &kbdus_tables
;
1020 TRACE_(keyboard
)( "chr %s, layout %p\n", debugstr_wn(&chr
, 1), layout
);
1022 if ((ret
= user_driver
->pVkKeyScanEx( chr
, layout
)) != -256) return ret
;
1023 ret
= kbd_tables_wchar_to_vkey( kbd_tables
, chr
);
1025 TRACE_(keyboard
)( "ret %04x\n", ret
);
1030 /******************************************************************************
1031 * NtUserMapVirtualKeyEx (win32u.@)
1033 UINT WINAPI
NtUserMapVirtualKeyEx( UINT code
, UINT type
, HKL layout
)
1035 const KBDTABLES
*kbd_tables
= &kbdus_tables
;
1036 BYTE vsc2vk
[0x300], vk2char
[0x100];
1039 TRACE_(keyboard
)( "code %u, type %u, layout %p.\n", code
, type
, layout
);
1041 if ((ret
= user_driver
->pMapVirtualKeyEx( code
, type
, layout
)) != -1) return ret
;
1043 kbd_tables_init_vsc2vk( kbd_tables
, vsc2vk
);
1044 kbd_tables_init_vk2char( kbd_tables
, vk2char
);
1048 case MAPVK_VK_TO_VSC_EX
:
1049 case MAPVK_VK_TO_VSC
:
1052 case VK_SHIFT
: code
= VK_LSHIFT
; break;
1053 case VK_CONTROL
: code
= VK_LCONTROL
; break;
1054 case VK_MENU
: code
= VK_LMENU
; break;
1055 case VK_NUMPAD0
: code
= VK_INSERT
; break;
1056 case VK_NUMPAD1
: code
= VK_END
; break;
1057 case VK_NUMPAD2
: code
= VK_DOWN
; break;
1058 case VK_NUMPAD3
: code
= VK_NEXT
; break;
1059 case VK_NUMPAD4
: code
= VK_LEFT
; break;
1060 case VK_NUMPAD5
: code
= VK_CLEAR
; break;
1061 case VK_NUMPAD6
: code
= VK_RIGHT
; break;
1062 case VK_NUMPAD7
: code
= VK_HOME
; break;
1063 case VK_NUMPAD8
: code
= VK_UP
; break;
1064 case VK_NUMPAD9
: code
= VK_PRIOR
; break;
1065 case VK_DECIMAL
: code
= VK_DELETE
; break;
1068 for (ret
= 0; ret
< ARRAY_SIZE(vsc2vk
); ++ret
) if (vsc2vk
[ret
] == code
) break;
1069 if (ret
>= ARRAY_SIZE(vsc2vk
)) ret
= 0;
1071 if (type
== MAPVK_VK_TO_VSC
)
1073 if (ret
>= 0x200) ret
= 0;
1076 else if (ret
>= 0x100) ret
+= 0xdf00;
1078 case MAPVK_VSC_TO_VK
:
1079 case MAPVK_VSC_TO_VK_EX
:
1080 if (code
& 0xe000) code
-= 0xdf00;
1081 if (code
>= ARRAY_SIZE(vsc2vk
)) ret
= 0;
1082 else ret
= vsc2vk
[code
];
1084 if (type
== MAPVK_VSC_TO_VK
)
1088 case VK_LSHIFT
: case VK_RSHIFT
: ret
= VK_SHIFT
; break;
1089 case VK_LCONTROL
: case VK_RCONTROL
: ret
= VK_CONTROL
; break;
1090 case VK_LMENU
: case VK_RMENU
: ret
= VK_MENU
; break;
1094 case MAPVK_VK_TO_CHAR
:
1095 if (code
>= ARRAY_SIZE(vk2char
)) ret
= 0;
1096 else if (code
>= 'A' && code
<= 'Z') ret
= code
;
1097 else ret
= vk2char
[code
];
1100 FIXME_(keyboard
)( "unknown type %d\n", type
);
1104 TRACE_(keyboard
)( "returning 0x%04x\n", ret
);
1108 /****************************************************************************
1109 * NtUserGetKeyNameText (win32u.@)
1111 INT WINAPI
NtUserGetKeyNameText( LONG lparam
, WCHAR
*buffer
, INT size
)
1113 INT code
= ((lparam
>> 16) & 0x1ff), vkey
, len
;
1114 const KBDTABLES
*kbd_tables
= &kbdus_tables
;
1115 VSC_LPWSTR
*key_name
;
1118 TRACE_(keyboard
)( "lparam %#x, buffer %p, size %d.\n", (int)lparam
, buffer
, size
);
1120 if (!buffer
|| !size
) return 0;
1121 if ((len
= user_driver
->pGetKeyNameText( lparam
, buffer
, size
)) >= 0) return len
;
1123 kbd_tables_init_vsc2vk( kbd_tables
, vsc2vk
);
1125 if (lparam
& 0x2000000)
1127 switch ((vkey
= vsc2vk
[code
]))
1132 for (code
= 0; code
< ARRAY_SIZE(vsc2vk
); ++code
)
1133 if (vsc2vk
[code
] == (vkey
- 1)) break;
1138 if (code
< 0x100) key_name
= kbd_tables
->pKeyNames
;
1139 else key_name
= kbd_tables
->pKeyNamesExt
;
1140 while (key_name
->vsc
&& key_name
->vsc
!= (BYTE
)code
) key_name
++;
1142 if (key_name
->vsc
== (BYTE
)code
)
1144 len
= min( size
- 1, wcslen( key_name
->pwsz
) );
1145 memcpy( buffer
, key_name
->pwsz
, len
* sizeof(WCHAR
) );
1149 HKL hkl
= NtUserGetKeyboardLayout( 0 );
1150 vkey
= NtUserMapVirtualKeyEx( code
& 0xff, MAPVK_VSC_TO_VK
, hkl
);
1151 buffer
[0] = NtUserMapVirtualKeyEx( vkey
, MAPVK_VK_TO_CHAR
, hkl
);
1156 TRACE_(keyboard
)( "ret %d, str %s.\n", len
, debugstr_w(buffer
) );
1160 /****************************************************************************
1161 * NtUserToUnicodeEx (win32u.@)
1163 INT WINAPI
NtUserToUnicodeEx( UINT virt
, UINT scan
, const BYTE
*state
,
1164 WCHAR
*str
, int size
, UINT flags
, HKL layout
)
1166 const KBDTABLES
*kbd_tables
= &kbdus_tables
;
1167 WCHAR buffer
[2] = {0};
1170 TRACE_(keyboard
)( "virt %#x, scan %#x, state %p, str %p, size %d, flags %#x, layout %p.\n",
1171 virt
, scan
, state
, str
, size
, flags
, layout
);
1173 if (!state
) return 0;
1174 if ((len
= user_driver
->pToUnicodeEx( virt
, scan
, state
, str
, size
, flags
, layout
)) >= -1)
1177 if (scan
& 0x8000) buffer
[0] = 0; /* key up */
1178 else buffer
[0] = kbd_tables_vkey_to_wchar( kbd_tables
, virt
, state
);
1180 if (buffer
[0] != WCH_NONE
) len
= 1;
1181 else buffer
[0] = len
= 0;
1183 lstrcpynW( str
, buffer
, size
);
1185 TRACE_(keyboard
)( "ret %d, str %s.\n", len
, debugstr_w(str
) );
1189 /**********************************************************************
1190 * NtUserActivateKeyboardLayout (win32u.@)
1192 HKL WINAPI
NtUserActivateKeyboardLayout( HKL layout
, UINT flags
)
1194 struct user_thread_info
*info
= get_user_thread_info();
1199 TRACE_(keyboard
)( "layout %p, flags %x\n", layout
, flags
);
1201 if (flags
) FIXME_(keyboard
)( "flags %x not supported\n", flags
);
1203 if (layout
== (HKL
)HKL_NEXT
|| layout
== (HKL
)HKL_PREV
)
1205 RtlSetLastWin32Error( ERROR_CALL_NOT_IMPLEMENTED
);
1206 FIXME_(keyboard
)( "HKL_NEXT and HKL_PREV not supported\n" );
1210 if (LOWORD(layout
) != MAKELANGID(LANG_INVARIANT
, SUBLANG_DEFAULT
) &&
1211 (NtQueryDefaultLocale( TRUE
, &locale
) || LOWORD(layout
) != locale
))
1213 RtlSetLastWin32Error( ERROR_CALL_NOT_IMPLEMENTED
);
1214 FIXME_(keyboard
)( "Changing user locale is not supported\n" );
1218 if (!user_driver
->pActivateKeyboardLayout( layout
, flags
))
1221 old_layout
= info
->kbd_layout
;
1222 if (old_layout
!= layout
)
1224 HWND ime_hwnd
= get_default_ime_window( 0 );
1225 const NLS_LOCALE_DATA
*data
;
1226 CHARSETINFO cs
= {0};
1228 if (ime_hwnd
) send_message( ime_hwnd
, WM_IME_INTERNAL
, IME_INTERNAL_HKL_DEACTIVATE
, HandleToUlong(old_layout
) );
1230 if (HIWORD(layout
) & 0x8000)
1231 FIXME( "Aliased keyboard layout not yet implemented\n" );
1232 else if (!(data
= get_locale_data( HIWORD(layout
) )))
1233 WARN( "Failed to find locale data for %04x\n", HIWORD(layout
) );
1235 translate_charset_info( ULongToPtr(data
->idefaultansicodepage
), &cs
, TCI_SRCCODEPAGE
);
1237 info
->kbd_layout
= layout
;
1238 info
->kbd_layout_id
= 0;
1240 if (ime_hwnd
) send_message( ime_hwnd
, WM_IME_INTERNAL
, IME_INTERNAL_HKL_ACTIVATE
, HandleToUlong(layout
) );
1242 if ((focus
= get_focus()) && get_window_thread( focus
, NULL
) == GetCurrentThreadId())
1243 send_message( focus
, WM_INPUTLANGCHANGE
, cs
.ciCharset
, (LPARAM
)layout
);
1246 if (!old_layout
) return get_locale_kbd_layout();
1252 /***********************************************************************
1253 * NtUserGetKeyboardLayoutList (win32u.@)
1255 * Return number of values available if either input parm is
1256 * 0, per MS documentation.
1258 UINT WINAPI
NtUserGetKeyboardLayoutList( INT size
, HKL
*layouts
)
1261 KEY_NODE_INFORMATION
*key_info
= (KEY_NODE_INFORMATION
*)buffer
;
1262 KEY_VALUE_PARTIAL_INFORMATION
*value_info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
1263 DWORD count
, tmp
, i
= 0;
1267 TRACE_(keyboard
)( "size %d, layouts %p.\n", size
, layouts
);
1269 if ((count
= user_driver
->pGetKeyboardLayoutList( size
, layouts
)) != ~0) return count
;
1271 layout
= get_locale_kbd_layout();
1275 if (size
&& layouts
)
1277 layouts
[count
- 1] = layout
;
1278 if (count
== size
) return count
;
1281 if ((hkey
= reg_open_key( NULL
, keyboard_layouts_keyW
, sizeof(keyboard_layouts_keyW
) )))
1283 while (!NtEnumerateKey( hkey
, i
++, KeyNodeInformation
, key_info
,
1284 sizeof(buffer
) - sizeof(WCHAR
), &tmp
))
1286 if (!(subkey
= reg_open_key( hkey
, key_info
->Name
, key_info
->NameLength
))) continue;
1287 key_info
->Name
[key_info
->NameLength
/ sizeof(WCHAR
)] = 0;
1288 tmp
= wcstoul( key_info
->Name
, NULL
, 16 );
1289 if (query_reg_ascii_value( subkey
, "Layout Id", value_info
, sizeof(buffer
) ) &&
1290 value_info
->Type
== REG_SZ
)
1291 tmp
= 0xf000 | (wcstoul( (const WCHAR
*)value_info
->Data
, NULL
, 16 ) & 0xfff);
1294 tmp
= MAKELONG( LOWORD( layout
), LOWORD( tmp
) );
1295 if (layout
== UlongToHandle( tmp
)) continue;
1298 if (size
&& layouts
)
1300 layouts
[count
- 1] = UlongToHandle( tmp
);
1301 if (count
== size
) break;
1310 /****************************************************************************
1311 * NtUserGetKeyboardLayoutName (win32u.@)
1313 BOOL WINAPI
NtUserGetKeyboardLayoutName( WCHAR
*name
)
1315 struct user_thread_info
*info
= get_user_thread_info();
1317 KEY_NODE_INFORMATION
*key
= (KEY_NODE_INFORMATION
*)buffer
;
1318 KEY_VALUE_PARTIAL_INFORMATION
*value
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
1319 WCHAR klid
[KL_NAMELENGTH
];
1325 TRACE_(keyboard
)( "name %p\n", name
);
1329 RtlSetLastWin32Error( ERROR_NOACCESS
);
1333 if (info
->kbd_layout_id
)
1335 sprintf( buffer
, "%08X", info
->kbd_layout_id
);
1336 asciiz_to_unicode( name
, buffer
);
1340 layout
= NtUserGetKeyboardLayout( 0 );
1341 id
= HandleToUlong( layout
);
1342 if (HIWORD( id
) == LOWORD( id
)) id
= LOWORD( id
);
1343 sprintf( buffer
, "%08X", id
);
1344 asciiz_to_unicode( name
, buffer
);
1346 if ((hkey
= reg_open_key( NULL
, keyboard_layouts_keyW
, sizeof(keyboard_layouts_keyW
) )))
1348 while (!NtEnumerateKey( hkey
, i
++, KeyNodeInformation
, key
,
1349 sizeof(buffer
) - sizeof(WCHAR
), &len
))
1351 if (!(subkey
= reg_open_key( hkey
, key
->Name
, key
->NameLength
))) continue;
1352 memcpy( klid
, key
->Name
, key
->NameLength
);
1353 klid
[key
->NameLength
/ sizeof(WCHAR
)] = 0;
1354 if (query_reg_ascii_value( subkey
, "Layout Id", value
, sizeof(buffer
) ) &&
1355 value
->Type
== REG_SZ
)
1356 id
= 0xf000 | (wcstoul( (const WCHAR
*)value
->Data
, NULL
, 16 ) & 0xfff);
1358 id
= wcstoul( klid
, NULL
, 16 );
1361 if (HIWORD( layout
) == id
)
1363 lstrcpynW( name
, klid
, KL_NAMELENGTH
);
1370 info
->kbd_layout_id
= wcstoul( name
, NULL
, 16 );
1372 TRACE_(keyboard
)( "ret %s\n", debugstr_w( name
) );
1376 /***********************************************************************
1377 * NtUserRegisterHotKey (win32u.@)
1379 BOOL WINAPI
NtUserRegisterHotKey( HWND hwnd
, INT id
, UINT modifiers
, UINT vk
)
1384 TRACE_(keyboard
)( "(%p,%d,0x%08x,%X)\n", hwnd
, id
, modifiers
, vk
);
1386 if ((!hwnd
|| is_current_thread_window( hwnd
)) &&
1387 !user_driver
->pRegisterHotKey( hwnd
, modifiers
, vk
))
1390 SERVER_START_REQ( register_hotkey
)
1392 req
->window
= wine_server_user_handle( hwnd
);
1394 req
->flags
= modifiers
;
1396 if ((ret
= !wine_server_call_err( req
)))
1398 replaced
= reply
->replaced
;
1399 modifiers
= reply
->flags
;
1405 if (ret
&& replaced
)
1406 user_driver
->pUnregisterHotKey(hwnd
, modifiers
, vk
);
1411 /***********************************************************************
1412 * NtUserUnregisterHotKey (win32u.@)
1414 BOOL WINAPI
NtUserUnregisterHotKey( HWND hwnd
, INT id
)
1419 TRACE_(keyboard
)("(%p,%d)\n",hwnd
,id
);
1421 SERVER_START_REQ( unregister_hotkey
)
1423 req
->window
= wine_server_user_handle( hwnd
);
1425 if ((ret
= !wine_server_call_err( req
)))
1427 modifiers
= reply
->flags
;
1434 user_driver
->pUnregisterHotKey(hwnd
, modifiers
, vk
);
1439 /***********************************************************************
1440 * NtUserGetMouseMovePointsEx (win32u.@)
1442 int WINAPI
NtUserGetMouseMovePointsEx( UINT size
, MOUSEMOVEPOINT
*ptin
, MOUSEMOVEPOINT
*ptout
,
1443 int count
, DWORD resolution
)
1445 cursor_pos_t
*pos
, positions
[64];
1450 TRACE( "%d, %p, %p, %d, %d\n", size
, ptin
, ptout
, count
, (int)resolution
);
1452 if ((size
!= sizeof(MOUSEMOVEPOINT
)) || (count
< 0) || (count
> ARRAY_SIZE( positions
)))
1454 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
1458 if (!ptin
|| (!ptout
&& count
))
1460 RtlSetLastWin32Error( ERROR_NOACCESS
);
1464 if (resolution
!= GMMP_USE_DISPLAY_POINTS
)
1466 FIXME( "only GMMP_USE_DISPLAY_POINTS is supported for now\n" );
1467 RtlSetLastWin32Error( ERROR_POINT_NOT_FOUND
);
1471 SERVER_START_REQ( get_cursor_history
)
1473 wine_server_set_reply( req
, &positions
, sizeof(positions
) );
1474 if (wine_server_call_err( req
)) return -1;
1478 for (i
= 0; i
< ARRAY_SIZE( positions
); i
++)
1480 pos
= &positions
[i
];
1481 if (ptin
->x
== pos
->x
&& ptin
->y
== pos
->y
&& (!ptin
->time
|| ptin
->time
== pos
->time
))
1485 if (i
== ARRAY_SIZE( positions
))
1487 RtlSetLastWin32Error( ERROR_POINT_NOT_FOUND
);
1491 for (copied
= 0; copied
< count
&& i
< ARRAY_SIZE( positions
); copied
++, i
++)
1493 pos
= &positions
[i
];
1494 ptout
[copied
].x
= pos
->x
;
1495 ptout
[copied
].y
= pos
->y
;
1496 ptout
[copied
].time
= pos
->time
;
1497 ptout
[copied
].dwExtraInfo
= pos
->info
;
1503 static WORD
get_key_state(void)
1507 if (get_system_metrics( SM_SWAPBUTTON
))
1509 if (NtUserGetAsyncKeyState(VK_RBUTTON
) & 0x80) ret
|= MK_LBUTTON
;
1510 if (NtUserGetAsyncKeyState(VK_LBUTTON
) & 0x80) ret
|= MK_RBUTTON
;
1514 if (NtUserGetAsyncKeyState(VK_LBUTTON
) & 0x80) ret
|= MK_LBUTTON
;
1515 if (NtUserGetAsyncKeyState(VK_RBUTTON
) & 0x80) ret
|= MK_RBUTTON
;
1517 if (NtUserGetAsyncKeyState(VK_MBUTTON
) & 0x80) ret
|= MK_MBUTTON
;
1518 if (NtUserGetAsyncKeyState(VK_SHIFT
) & 0x80) ret
|= MK_SHIFT
;
1519 if (NtUserGetAsyncKeyState(VK_CONTROL
) & 0x80) ret
|= MK_CONTROL
;
1520 if (NtUserGetAsyncKeyState(VK_XBUTTON1
) & 0x80) ret
|= MK_XBUTTON1
;
1521 if (NtUserGetAsyncKeyState(VK_XBUTTON2
) & 0x80) ret
|= MK_XBUTTON2
;
1525 struct tracking_list
1527 TRACKMOUSEEVENT info
;
1528 POINT pos
; /* center of hover rectangle */
1531 /* FIXME: move tracking stuff into per-thread data */
1532 static struct tracking_list tracking_info
;
1534 static void check_mouse_leave( HWND hwnd
, int hittest
)
1536 if (tracking_info
.info
.hwndTrack
!= hwnd
)
1538 if (tracking_info
.info
.dwFlags
& TME_NONCLIENT
)
1539 NtUserPostMessage( tracking_info
.info
.hwndTrack
, WM_NCMOUSELEAVE
, 0, 0 );
1541 NtUserPostMessage( tracking_info
.info
.hwndTrack
, WM_MOUSELEAVE
, 0, 0 );
1543 tracking_info
.info
.dwFlags
&= ~TME_LEAVE
;
1547 if (hittest
== HTCLIENT
)
1549 if (tracking_info
.info
.dwFlags
& TME_NONCLIENT
)
1551 NtUserPostMessage( tracking_info
.info
.hwndTrack
, WM_NCMOUSELEAVE
, 0, 0 );
1552 tracking_info
.info
.dwFlags
&= ~TME_LEAVE
;
1557 if (!(tracking_info
.info
.dwFlags
& TME_NONCLIENT
))
1559 NtUserPostMessage( tracking_info
.info
.hwndTrack
, WM_MOUSELEAVE
, 0, 0 );
1560 tracking_info
.info
.dwFlags
&= ~TME_LEAVE
;
1566 void update_mouse_tracking_info( HWND hwnd
)
1568 int hover_width
= 0, hover_height
= 0, hittest
;
1571 TRACE( "hwnd %p\n", hwnd
);
1573 get_cursor_pos( &pos
);
1574 hwnd
= window_from_point( hwnd
, pos
, &hittest
);
1576 TRACE( "point %s hwnd %p hittest %d\n", wine_dbgstr_point(&pos
), hwnd
, hittest
);
1578 NtUserSystemParametersInfo( SPI_GETMOUSEHOVERWIDTH
, 0, &hover_width
, 0 );
1579 NtUserSystemParametersInfo( SPI_GETMOUSEHOVERHEIGHT
, 0, &hover_height
, 0 );
1581 TRACE( "tracked pos %s, current pos %s, hover width %d, hover height %d\n",
1582 wine_dbgstr_point(&tracking_info
.pos
), wine_dbgstr_point(&pos
),
1583 hover_width
, hover_height
);
1585 if (tracking_info
.info
.dwFlags
& TME_LEAVE
)
1586 check_mouse_leave( hwnd
, hittest
);
1588 if (tracking_info
.info
.hwndTrack
!= hwnd
)
1589 tracking_info
.info
.dwFlags
&= ~TME_HOVER
;
1591 if (tracking_info
.info
.dwFlags
& TME_HOVER
)
1593 /* has the cursor moved outside the rectangle centered around pos? */
1594 if ((abs( pos
.x
- tracking_info
.pos
.x
) > (hover_width
/ 2)) ||
1595 (abs( pos
.y
- tracking_info
.pos
.y
) > (hover_height
/ 2)))
1597 tracking_info
.pos
= pos
;
1601 if (hittest
== HTCLIENT
)
1603 screen_to_client(hwnd
, &pos
);
1604 TRACE( "client cursor pos %s\n", wine_dbgstr_point(&pos
) );
1606 NtUserPostMessage( tracking_info
.info
.hwndTrack
, WM_MOUSEHOVER
,
1607 get_key_state(), MAKELPARAM( pos
.x
, pos
.y
) );
1611 if (tracking_info
.info
.dwFlags
& TME_NONCLIENT
)
1612 NtUserPostMessage( tracking_info
.info
.hwndTrack
, WM_NCMOUSEHOVER
,
1613 hittest
, MAKELPARAM( pos
.x
, pos
.y
) );
1616 /* stop tracking mouse hover */
1617 tracking_info
.info
.dwFlags
&= ~TME_HOVER
;
1621 /* stop the timer if the tracking list is empty */
1622 if (!(tracking_info
.info
.dwFlags
& (TME_HOVER
| TME_LEAVE
)))
1624 kill_system_timer( tracking_info
.info
.hwndTrack
, SYSTEM_TIMER_TRACK_MOUSE
);
1625 tracking_info
.info
.hwndTrack
= 0;
1626 tracking_info
.info
.dwFlags
= 0;
1627 tracking_info
.info
.dwHoverTime
= 0;
1631 /***********************************************************************
1632 * NtUserTrackMouseEvent (win32u.@)
1634 BOOL WINAPI
NtUserTrackMouseEvent( TRACKMOUSEEVENT
*info
)
1641 TRACE( "size %u, flags %#x, hwnd %p, time %u\n",
1642 (int)info
->cbSize
, (int)info
->dwFlags
, info
->hwndTrack
, (int)info
->dwHoverTime
);
1644 if (info
->cbSize
!= sizeof(TRACKMOUSEEVENT
))
1646 WARN( "wrong size %u\n", (int)info
->cbSize
);
1647 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
1651 if (info
->dwFlags
& TME_QUERY
)
1653 *info
= tracking_info
.info
;
1654 info
->cbSize
= sizeof(TRACKMOUSEEVENT
);
1658 if (!is_window( info
->hwndTrack
))
1660 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
1664 hover_time
= (info
->dwFlags
& TME_HOVER
) ? info
->dwHoverTime
: HOVER_DEFAULT
;
1666 if (hover_time
== HOVER_DEFAULT
|| hover_time
== 0)
1667 NtUserSystemParametersInfo( SPI_GETMOUSEHOVERTIME
, 0, &hover_time
, 0 );
1669 get_cursor_pos( &pos
);
1670 hwnd
= window_from_point( info
->hwndTrack
, pos
, &hittest
);
1671 TRACE( "point %s hwnd %p hittest %d\n", wine_dbgstr_point(&pos
), hwnd
, hittest
);
1673 if (info
->dwFlags
& ~(TME_CANCEL
| TME_HOVER
| TME_LEAVE
| TME_NONCLIENT
))
1674 FIXME( "ignoring flags %#x\n", (int)info
->dwFlags
& ~(TME_CANCEL
| TME_HOVER
| TME_LEAVE
| TME_NONCLIENT
) );
1676 if (info
->dwFlags
& TME_CANCEL
)
1678 if (tracking_info
.info
.hwndTrack
== info
->hwndTrack
)
1680 tracking_info
.info
.dwFlags
&= ~(info
->dwFlags
& ~TME_CANCEL
);
1682 /* if we aren't tracking on hover or leave remove this entry */
1683 if (!(tracking_info
.info
.dwFlags
& (TME_HOVER
| TME_LEAVE
)))
1685 kill_system_timer( tracking_info
.info
.hwndTrack
, SYSTEM_TIMER_TRACK_MOUSE
);
1686 tracking_info
.info
.hwndTrack
= 0;
1687 tracking_info
.info
.dwFlags
= 0;
1688 tracking_info
.info
.dwHoverTime
= 0;
1694 /* In our implementation, it's possible that another window will receive
1695 * WM_MOUSEMOVE and call TrackMouseEvent before TrackMouseEventProc is
1696 * called. In such a situation, post the WM_MOUSELEAVE now. */
1697 if ((tracking_info
.info
.dwFlags
& TME_LEAVE
) && tracking_info
.info
.hwndTrack
!= NULL
)
1698 check_mouse_leave(hwnd
, hittest
);
1700 kill_system_timer( tracking_info
.info
.hwndTrack
, SYSTEM_TIMER_TRACK_MOUSE
);
1701 tracking_info
.info
.hwndTrack
= 0;
1702 tracking_info
.info
.dwFlags
= 0;
1703 tracking_info
.info
.dwHoverTime
= 0;
1705 if (info
->hwndTrack
== hwnd
)
1707 /* Adding new mouse event to the tracking list */
1708 tracking_info
.info
= *info
;
1709 tracking_info
.info
.dwHoverTime
= hover_time
;
1711 /* Initialize HoverInfo variables even if not hover tracking */
1712 tracking_info
.pos
= pos
;
1714 NtUserSetSystemTimer( tracking_info
.info
.hwndTrack
, SYSTEM_TIMER_TRACK_MOUSE
, hover_time
);
1721 /**********************************************************************
1722 * set_capture_window
1724 BOOL
set_capture_window( HWND hwnd
, UINT gui_flags
, HWND
*prev_ret
)
1730 if (gui_flags
& GUI_INMENUMODE
) flags
|= CAPTURE_MENU
;
1731 if (gui_flags
& GUI_INMOVESIZE
) flags
|= CAPTURE_MOVESIZE
;
1733 SERVER_START_REQ( set_capture_window
)
1735 req
->handle
= wine_server_user_handle( hwnd
);
1737 if ((ret
= !wine_server_call_err( req
)))
1739 previous
= wine_server_ptr_handle( reply
->previous
);
1740 hwnd
= wine_server_ptr_handle( reply
->full_handle
);
1747 user_driver
->pSetCapture( hwnd
, gui_flags
);
1750 send_message( previous
, WM_CAPTURECHANGED
, 0, (LPARAM
)hwnd
);
1752 if (prev_ret
) *prev_ret
= previous
;
1757 /**********************************************************************
1758 * NtUserSetCapture (win32u.@)
1760 HWND WINAPI
NtUserSetCapture( HWND hwnd
)
1764 set_capture_window( hwnd
, 0, &previous
);
1768 /**********************************************************************
1771 BOOL
release_capture(void)
1773 BOOL ret
= set_capture_window( 0, 0, NULL
);
1775 /* Somebody may have missed some mouse movements */
1778 INPUT input
= { .type
= INPUT_MOUSE
};
1779 input
.mi
.dwFlags
= MOUSEEVENTF_MOVE
;
1780 NtUserSendInput( 1, &input
, sizeof(input
) );
1786 /*****************************************************************
1789 * Change the focus window, sending the WM_SETFOCUS and WM_KILLFOCUS messages
1791 static HWND
set_focus_window( HWND hwnd
)
1793 HWND previous
= 0, ime_hwnd
;
1796 SERVER_START_REQ( set_focus_window
)
1798 req
->handle
= wine_server_user_handle( hwnd
);
1799 if ((ret
= !wine_server_call_err( req
)))
1800 previous
= wine_server_ptr_handle( reply
->previous
);
1804 if (previous
== hwnd
) return previous
;
1808 send_message( previous
, WM_KILLFOCUS
, (WPARAM
)hwnd
, 0 );
1810 ime_hwnd
= get_default_ime_window( previous
);
1812 send_message( ime_hwnd
, WM_IME_INTERNAL
, IME_INTERNAL_DEACTIVATE
,
1813 HandleToUlong(previous
) );
1815 if (hwnd
!= get_focus()) return previous
; /* changed by the message */
1817 if (is_window(hwnd
))
1819 user_driver
->pSetFocus(hwnd
);
1821 ime_hwnd
= get_default_ime_window( hwnd
);
1823 send_message( ime_hwnd
, WM_IME_INTERNAL
, IME_INTERNAL_ACTIVATE
,
1824 HandleToUlong(hwnd
) );
1827 NtUserNotifyWinEvent( EVENT_OBJECT_FOCUS
, hwnd
, OBJID_CLIENT
, 0 );
1829 send_message( hwnd
, WM_SETFOCUS
, (WPARAM
)previous
, 0 );
1834 /*******************************************************************
1837 static BOOL
set_active_window( HWND hwnd
, HWND
*prev
, BOOL mouse
, BOOL focus
)
1839 HWND previous
= get_active_window();
1841 DWORD old_thread
, new_thread
;
1842 CBTACTIVATESTRUCT cbt
;
1844 if (previous
== hwnd
)
1846 if (prev
) *prev
= hwnd
;
1850 /* call CBT hook chain */
1852 cbt
.hWndActive
= previous
;
1853 if (call_hooks( WH_CBT
, HCBT_ACTIVATE
, (WPARAM
)hwnd
, (LPARAM
)&cbt
, sizeof(cbt
) )) return FALSE
;
1855 if (is_window( previous
))
1857 send_message( previous
, WM_NCACTIVATE
, FALSE
, (LPARAM
)hwnd
);
1858 send_message( previous
, WM_ACTIVATE
,
1859 MAKEWPARAM( WA_INACTIVE
, is_iconic(previous
) ), (LPARAM
)hwnd
);
1862 SERVER_START_REQ( set_active_window
)
1864 req
->handle
= wine_server_user_handle( hwnd
);
1865 if ((ret
= !wine_server_call_err( req
)))
1866 previous
= wine_server_ptr_handle( reply
->previous
);
1869 if (!ret
) return FALSE
;
1870 if (prev
) *prev
= previous
;
1871 if (previous
== hwnd
) return TRUE
;
1875 /* send palette messages */
1876 if (send_message( hwnd
, WM_QUERYNEWPALETTE
, 0, 0 ))
1877 send_message_timeout( HWND_BROADCAST
, WM_PALETTEISCHANGING
, (WPARAM
)hwnd
, 0,
1878 SMTO_ABORTIFHUNG
, 2000, FALSE
);
1879 if (!is_window(hwnd
)) return FALSE
;
1882 old_thread
= previous
? get_window_thread( previous
, NULL
) : 0;
1883 new_thread
= hwnd
? get_window_thread( hwnd
, NULL
) : 0;
1885 if (old_thread
!= new_thread
)
1889 if ((list
= list_window_children( NULL
, get_desktop_window(), NULL
, 0 )))
1893 for (phwnd
= list
; *phwnd
; phwnd
++)
1895 if (get_window_thread( *phwnd
, NULL
) == old_thread
)
1896 send_message( *phwnd
, WM_ACTIVATEAPP
, 0, new_thread
);
1901 for (phwnd
= list
; *phwnd
; phwnd
++)
1903 if (get_window_thread( *phwnd
, NULL
) == new_thread
)
1904 send_message( *phwnd
, WM_ACTIVATEAPP
, 1, old_thread
);
1911 if (is_window(hwnd
))
1913 send_message( hwnd
, WM_NCACTIVATE
, hwnd
== NtUserGetForegroundWindow(), (LPARAM
)previous
);
1914 send_message( hwnd
, WM_ACTIVATE
,
1915 MAKEWPARAM( mouse
? WA_CLICKACTIVE
: WA_ACTIVE
, is_iconic(hwnd
) ),
1917 if (NtUserGetAncestor( hwnd
, GA_PARENT
) == get_desktop_window())
1918 NtUserPostMessage( get_desktop_window(), WM_PARENTNOTIFY
, WM_NCACTIVATE
, (LPARAM
)hwnd
);
1921 /* now change focus if necessary */
1926 info
.cbSize
= sizeof(info
);
1927 NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info
);
1928 /* Do not change focus if the window is no more active */
1929 if (hwnd
== info
.hwndActive
)
1931 if (!info
.hwndFocus
|| !hwnd
|| NtUserGetAncestor( info
.hwndFocus
, GA_ROOT
) != hwnd
)
1932 set_focus_window( hwnd
);
1939 /**********************************************************************
1940 * NtUserSetActiveWindow (win32u.@)
1942 HWND WINAPI
NtUserSetActiveWindow( HWND hwnd
)
1946 TRACE( "%p\n", hwnd
);
1952 hwnd
= get_full_window_handle( hwnd
);
1953 if (!is_window( hwnd
))
1955 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
1959 style
= get_window_long( hwnd
, GWL_STYLE
);
1960 if ((style
& (WS_POPUP
|WS_CHILD
)) == WS_CHILD
)
1961 return get_active_window(); /* Windows doesn't seem to return an error here */
1964 if (!set_active_window( hwnd
, &prev
, FALSE
, TRUE
)) return 0;
1968 /*****************************************************************
1969 * NtUserSetFocus (win32u.@)
1971 HWND WINAPI
NtUserSetFocus( HWND hwnd
)
1973 HWND hwndTop
= hwnd
;
1974 HWND previous
= get_focus();
1976 TRACE( "%p prev %p\n", hwnd
, previous
);
1980 /* Check if we can set the focus to this window */
1981 hwnd
= get_full_window_handle( hwnd
);
1982 if (!is_window( hwnd
))
1984 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
1987 if (hwnd
== previous
) return previous
; /* nothing to do */
1991 LONG style
= get_window_long( hwndTop
, GWL_STYLE
);
1992 if (style
& (WS_MINIMIZE
| WS_DISABLED
)) return 0;
1993 if (!(style
& WS_CHILD
)) break;
1994 parent
= NtUserGetAncestor( hwndTop
, GA_PARENT
);
1995 if (!parent
|| parent
== get_desktop_window())
1997 if ((style
& (WS_POPUP
|WS_CHILD
)) == WS_CHILD
) return 0;
2000 if (parent
== get_hwnd_message_parent()) return 0;
2005 if (call_hooks( WH_CBT
, HCBT_SETFOCUS
, (WPARAM
)hwnd
, (LPARAM
)previous
, 0 )) return 0;
2007 /* activate hwndTop if needed. */
2008 if (hwndTop
!= get_active_window())
2010 if (!set_active_window( hwndTop
, NULL
, FALSE
, FALSE
)) return 0;
2011 if (!is_window( hwnd
)) return 0; /* Abort if window destroyed */
2013 /* Do not change focus if the window is no longer active */
2014 if (hwndTop
!= get_active_window()) return 0;
2017 else /* NULL hwnd passed in */
2019 if (!previous
) return 0; /* nothing to do */
2020 if (call_hooks( WH_CBT
, HCBT_SETFOCUS
, 0, (LPARAM
)previous
, 0 )) return 0;
2023 /* change focus and send messages */
2024 return set_focus_window( hwnd
);
2027 /*******************************************************************
2028 * set_foreground_window
2030 BOOL
set_foreground_window( HWND hwnd
, BOOL mouse
)
2032 BOOL ret
, send_msg_old
= FALSE
, send_msg_new
= FALSE
;
2035 if (mouse
) hwnd
= get_full_window_handle( hwnd
);
2037 SERVER_START_REQ( set_foreground_window
)
2039 req
->handle
= wine_server_user_handle( hwnd
);
2040 if ((ret
= !wine_server_call_err( req
)))
2042 previous
= wine_server_ptr_handle( reply
->previous
);
2043 send_msg_old
= reply
->send_msg_old
;
2044 send_msg_new
= reply
->send_msg_new
;
2049 if (ret
&& previous
!= hwnd
)
2051 if (send_msg_old
) /* old window belongs to other thread */
2052 NtUserMessageCall( previous
, WM_WINE_SETACTIVEWINDOW
, 0, 0,
2053 0, NtUserSendNotifyMessage
, FALSE
);
2054 else if (send_msg_new
) /* old window belongs to us but new one to other thread */
2055 ret
= set_active_window( 0, NULL
, mouse
, TRUE
);
2057 if (send_msg_new
) /* new window belongs to other thread */
2058 NtUserMessageCall( hwnd
, WM_WINE_SETACTIVEWINDOW
, (WPARAM
)hwnd
, 0,
2059 0, NtUserSendNotifyMessage
, FALSE
);
2060 else /* new window belongs to us */
2061 ret
= set_active_window( hwnd
, NULL
, mouse
, TRUE
);
2069 unsigned int timeout
;
2072 static void display_caret( HWND hwnd
, const RECT
*r
)
2076 /* do not use DCX_CACHE here, since coördinates are in logical units */
2077 if (!(dc
= NtUserGetDCEx( hwnd
, 0, DCX_USESTYLE
)))
2079 mem_dc
= NtGdiCreateCompatibleDC(dc
);
2082 HBITMAP prev_bitmap
;
2084 prev_bitmap
= NtGdiSelectBitmap( mem_dc
, caret
.bitmap
);
2085 NtGdiBitBlt( dc
, r
->left
, r
->top
, r
->right
-r
->left
, r
->bottom
-r
->top
, mem_dc
, 0, 0, SRCINVERT
, 0, 0 );
2086 NtGdiSelectBitmap( mem_dc
, prev_bitmap
);
2087 NtGdiDeleteObjectApp( mem_dc
);
2089 NtUserReleaseDC( hwnd
, dc
);
2092 static unsigned int get_caret_registry_timeout(void)
2094 char value_buffer
[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[11 * sizeof(WCHAR
)])];
2095 KEY_VALUE_PARTIAL_INFORMATION
*value
= (void *)value_buffer
;
2096 unsigned int ret
= 500;
2099 if (!(key
= reg_open_hkcu_key( "Control Panel\\Desktop" )))
2102 if (query_reg_ascii_value( key
, "CursorBlinkRate", value
, sizeof(value_buffer
) ))
2103 ret
= wcstoul( (WCHAR
*)value
->Data
, NULL
, 10 );
2108 /*****************************************************************
2109 * NtUserCreateCaret (win32u.@)
2111 BOOL WINAPI
NtUserCreateCaret( HWND hwnd
, HBITMAP bitmap
, int width
, int height
)
2113 HBITMAP caret_bitmap
= 0;
2120 TRACE( "hwnd %p, bitmap %p, width %d, height %d\n", hwnd
, bitmap
, width
, height
);
2122 if (!hwnd
) return FALSE
;
2124 if (bitmap
&& bitmap
!= (HBITMAP
)1)
2128 if (!NtGdiExtGetObjectW( bitmap
, sizeof(bitmap_data
), &bitmap_data
)) return FALSE
;
2129 width
= bitmap_data
.bmWidth
;
2130 height
= bitmap_data
.bmHeight
;
2131 caret_bitmap
= NtGdiCreateBitmap( bitmap_data
.bmWidth
, bitmap_data
.bmHeight
,
2132 bitmap_data
.bmPlanes
, bitmap_data
.bmBitsPixel
, NULL
);
2135 size_t size
= bitmap_data
.bmWidthBytes
* bitmap_data
.bmHeight
;
2136 BYTE
*bits
= malloc( size
);
2138 NtGdiGetBitmapBits( bitmap
, size
, bits
);
2139 NtGdiSetBitmapBits( caret_bitmap
, size
, bits
);
2147 if (!width
) width
= get_system_metrics( SM_CXBORDER
);
2148 if (!height
) height
= get_system_metrics( SM_CYBORDER
);
2150 /* create the uniform bitmap on the fly */
2151 dc
= NtUserGetDCEx( hwnd
, 0, DCX_USESTYLE
);
2154 HDC mem_dc
= NtGdiCreateCompatibleDC( dc
);
2157 if ((caret_bitmap
= NtGdiCreateCompatibleBitmap( mem_dc
, width
, height
)))
2159 HBITMAP prev_bitmap
= NtGdiSelectBitmap( mem_dc
, caret_bitmap
);
2160 SetRect( &r
, 0, 0, width
, height
);
2161 fill_rect( mem_dc
, &r
, GetStockObject( bitmap
? GRAY_BRUSH
: WHITE_BRUSH
));
2162 NtGdiSelectBitmap( mem_dc
, prev_bitmap
);
2164 NtGdiDeleteObjectApp( mem_dc
);
2166 NtUserReleaseDC( hwnd
, dc
);
2169 if (!caret_bitmap
) return FALSE
;
2171 SERVER_START_REQ( set_caret_window
)
2173 req
->handle
= wine_server_user_handle( hwnd
);
2175 req
->height
= height
;
2176 if ((ret
= !wine_server_call_err( req
)))
2178 prev
= wine_server_ptr_handle( reply
->previous
);
2179 r
.left
= reply
->old_rect
.left
;
2180 r
.top
= reply
->old_rect
.top
;
2181 r
.right
= reply
->old_rect
.right
;
2182 r
.bottom
= reply
->old_rect
.bottom
;
2183 old_state
= reply
->old_state
;
2184 hidden
= reply
->old_hide
;
2188 if (!ret
) return FALSE
;
2190 if (prev
&& !hidden
) /* hide the previous one */
2192 /* FIXME: won't work if prev belongs to a different process */
2193 kill_system_timer( prev
, SYSTEM_TIMER_CARET
);
2194 if (old_state
) display_caret( prev
, &r
);
2197 if (caret
.bitmap
) NtGdiDeleteObjectApp( caret
.bitmap
);
2198 caret
.bitmap
= caret_bitmap
;
2199 caret
.timeout
= get_caret_registry_timeout();
2203 /*******************************************************************
2206 BOOL
destroy_caret(void)
2214 SERVER_START_REQ( set_caret_window
)
2219 if ((ret
= !wine_server_call_err( req
)))
2221 prev
= wine_server_ptr_handle( reply
->previous
);
2222 r
.left
= reply
->old_rect
.left
;
2223 r
.top
= reply
->old_rect
.top
;
2224 r
.right
= reply
->old_rect
.right
;
2225 r
.bottom
= reply
->old_rect
.bottom
;
2226 old_state
= reply
->old_state
;
2227 hidden
= reply
->old_hide
;
2232 if (ret
&& prev
&& !hidden
)
2234 /* FIXME: won't work if prev belongs to a different process */
2235 kill_system_timer( prev
, SYSTEM_TIMER_CARET
);
2236 if (old_state
) display_caret( prev
, &r
);
2238 if (caret
.bitmap
) NtGdiDeleteObjectApp( caret
.bitmap
);
2243 /*****************************************************************
2244 * NtUserGetCaretBlinkTime (win32u.@)
2246 UINT WINAPI
NtUserGetCaretBlinkTime(void)
2248 return caret
.timeout
;
2251 /*******************************************************************
2252 * set_caret_blink_time
2254 BOOL
set_caret_blink_time( unsigned int time
)
2256 TRACE( "time %u\n", time
);
2258 caret
.timeout
= time
;
2259 /* FIXME: update the timer */
2263 /*****************************************************************
2264 * NtUserGetCaretPos (win32u.@)
2266 BOOL WINAPI
NtUserGetCaretPos( POINT
*pt
)
2270 SERVER_START_REQ( set_caret_info
)
2272 req
->flags
= 0; /* don't set anything */
2278 if ((ret
= !wine_server_call_err( req
)))
2280 pt
->x
= reply
->old_rect
.left
;
2281 pt
->y
= reply
->old_rect
.top
;
2288 /*******************************************************************
2291 BOOL
set_caret_pos( int x
, int y
)
2299 TRACE( "(%d, %d)\n", x
, y
);
2301 SERVER_START_REQ( set_caret_info
)
2303 req
->flags
= SET_CARET_POS
|SET_CARET_STATE
;
2308 req
->state
= CARET_STATE_ON_IF_MOVED
;
2309 if ((ret
= !wine_server_call_err( req
)))
2311 hwnd
= wine_server_ptr_handle( reply
->full_handle
);
2312 r
.left
= reply
->old_rect
.left
;
2313 r
.top
= reply
->old_rect
.top
;
2314 r
.right
= reply
->old_rect
.right
;
2315 r
.bottom
= reply
->old_rect
.bottom
;
2316 old_state
= reply
->old_state
;
2317 hidden
= reply
->old_hide
;
2321 if (ret
&& !hidden
&& (x
!= r
.left
|| y
!= r
.top
))
2323 if (old_state
) display_caret( hwnd
, &r
);
2324 r
.right
+= x
- r
.left
;
2325 r
.bottom
+= y
- r
.top
;
2328 display_caret( hwnd
, &r
);
2329 NtUserSetSystemTimer( hwnd
, SYSTEM_TIMER_CARET
, caret
.timeout
);
2334 /*****************************************************************
2335 * NtUserShowCaret (win32u.@)
2337 BOOL WINAPI
NtUserShowCaret( HWND hwnd
)
2343 SERVER_START_REQ( set_caret_info
)
2345 req
->flags
= SET_CARET_HIDE
| SET_CARET_STATE
;
2346 req
->handle
= wine_server_user_handle( hwnd
);
2350 req
->state
= CARET_STATE_ON
;
2351 if ((ret
= !wine_server_call_err( req
)))
2353 hwnd
= wine_server_ptr_handle( reply
->full_handle
);
2354 r
.left
= reply
->old_rect
.left
;
2355 r
.top
= reply
->old_rect
.top
;
2356 r
.right
= reply
->old_rect
.right
;
2357 r
.bottom
= reply
->old_rect
.bottom
;
2358 hidden
= reply
->old_hide
;
2363 if (ret
&& hidden
== 1) /* hidden was 1 so it's now 0 */
2365 display_caret( hwnd
, &r
);
2366 NtUserSetSystemTimer( hwnd
, SYSTEM_TIMER_CARET
, caret
.timeout
);
2371 /*****************************************************************
2372 * NtUserHideCaret (win32u.@)
2374 BOOL WINAPI
NtUserHideCaret( HWND hwnd
)
2381 SERVER_START_REQ( set_caret_info
)
2383 req
->flags
= SET_CARET_HIDE
| SET_CARET_STATE
;
2384 req
->handle
= wine_server_user_handle( hwnd
);
2388 req
->state
= CARET_STATE_OFF
;
2389 if ((ret
= !wine_server_call_err( req
)))
2391 hwnd
= wine_server_ptr_handle( reply
->full_handle
);
2392 r
.left
= reply
->old_rect
.left
;
2393 r
.top
= reply
->old_rect
.top
;
2394 r
.right
= reply
->old_rect
.right
;
2395 r
.bottom
= reply
->old_rect
.bottom
;
2396 old_state
= reply
->old_state
;
2397 hidden
= reply
->old_hide
;
2404 if (old_state
) display_caret( hwnd
, &r
);
2405 kill_system_timer( hwnd
, SYSTEM_TIMER_CARET
);
2410 void toggle_caret( HWND hwnd
)
2416 SERVER_START_REQ( set_caret_info
)
2418 req
->flags
= SET_CARET_STATE
;
2419 req
->handle
= wine_server_user_handle( hwnd
);
2423 req
->state
= CARET_STATE_TOGGLE
;
2424 if ((ret
= !wine_server_call( req
)))
2426 hwnd
= wine_server_ptr_handle( reply
->full_handle
);
2427 r
.left
= reply
->old_rect
.left
;
2428 r
.top
= reply
->old_rect
.top
;
2429 r
.right
= reply
->old_rect
.right
;
2430 r
.bottom
= reply
->old_rect
.bottom
;
2431 hidden
= reply
->old_hide
;
2436 if (ret
&& !hidden
) display_caret( hwnd
, &r
);
2440 /**********************************************************************
2441 * NtUserEnableMouseInPointer (win32u.@)
2443 BOOL WINAPI
NtUserEnableMouseInPointer( BOOL enable
)
2445 FIXME( "enable %u stub!\n", enable
);
2446 RtlSetLastWin32Error( ERROR_CALL_NOT_IMPLEMENTED
);
2450 /**********************************************************************
2451 * NtUserIsMouseInPointerEnabled (win32u.@)
2453 BOOL WINAPI
NtUserIsMouseInPointerEnabled(void)
2456 RtlSetLastWin32Error( ERROR_CALL_NOT_IMPLEMENTED
);
2460 /**********************************************************************
2461 * NtUserGetPointerInfoList (win32u.@)
2463 BOOL WINAPI
NtUserGetPointerInfoList( UINT32 id
, POINTER_INPUT_TYPE type
, UINT_PTR unk0
, UINT_PTR unk1
, SIZE_T size
,
2464 UINT32
*entry_count
, UINT32
*pointer_count
, void *pointer_info
)
2466 FIXME( "id %#x, type %#x, unk0 %#zx, unk1 %#zx, size %#zx, entry_count %p, pointer_count %p, pointer_info %p stub!\n",
2467 id
, (int)type
, (size_t)unk0
, (size_t)unk1
, (size_t)size
, entry_count
, pointer_count
, pointer_info
);
2468 RtlSetLastWin32Error( ERROR_CALL_NOT_IMPLEMENTED
);
2472 BOOL
get_clip_cursor( RECT
*rect
)
2477 if (!rect
) return FALSE
;
2479 SERVER_START_REQ( set_cursor
)
2482 if ((ret
= !wine_server_call( req
)))
2484 rect
->left
= reply
->new_clip
.left
;
2485 rect
->top
= reply
->new_clip
.top
;
2486 rect
->right
= reply
->new_clip
.right
;
2487 rect
->bottom
= reply
->new_clip
.bottom
;
2492 if (ret
&& (dpi
= get_thread_dpi()))
2494 HMONITOR monitor
= monitor_from_rect( rect
, MONITOR_DEFAULTTOPRIMARY
, 0 );
2495 *rect
= map_dpi_rect( *rect
, get_monitor_dpi( monitor
), dpi
);
2500 BOOL
process_wine_clipcursor( BOOL empty
)
2504 TRACE( "empty %u\n", empty
);
2506 if (empty
) return user_driver
->pClipCursor( NULL
);
2508 get_clip_cursor( &rect
);
2509 return user_driver
->pClipCursor( &rect
);
2512 /***********************************************************************
2513 * NtUserClipCursor (win32u.@)
2515 BOOL WINAPI
NtUserClipCursor( const RECT
*rect
)
2521 TRACE( "Clipping to %s\n", wine_dbgstr_rect(rect
) );
2525 if (rect
->left
> rect
->right
|| rect
->top
> rect
->bottom
) return FALSE
;
2526 if ((dpi
= get_thread_dpi()))
2528 HMONITOR monitor
= monitor_from_rect( rect
, MONITOR_DEFAULTTOPRIMARY
, dpi
);
2529 new_rect
= map_dpi_rect( *rect
, dpi
, get_monitor_dpi( monitor
));
2534 SERVER_START_REQ( set_cursor
)
2538 req
->flags
= SET_CURSOR_CLIP
;
2539 req
->clip
.left
= rect
->left
;
2540 req
->clip
.top
= rect
->top
;
2541 req
->clip
.right
= rect
->right
;
2542 req
->clip
.bottom
= rect
->bottom
;
2544 else req
->flags
= SET_CURSOR_NOCLIP
;
2546 if ((ret
= !wine_server_call( req
)))
2548 new_rect
.left
= reply
->new_clip
.left
;
2549 new_rect
.top
= reply
->new_clip
.top
;
2550 new_rect
.right
= reply
->new_clip
.right
;
2551 new_rect
.bottom
= reply
->new_clip
.bottom
;
2555 if (ret
) user_driver
->pClipCursor( &new_rect
);