win32u: Move set_foreground_window implementation from user32.
[wine.git] / dlls / win32u / input.c
blob33ce86a16755f5ae403f77b776ba35d4871eab78
1 /*
2 * USER Input processing
4 * Copyright 1993 Bob Amstadt
5 * Copyright 1996 Albrecht Kleine
6 * Copyright 1997 David Faure
7 * Copyright 1998 Morten Welinder
8 * Copyright 1998 Ulrich Weigand
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #if 0
26 #pragma makedep unix
27 #endif
29 #include "win32u_private.h"
30 #include "ntuser_private.h"
31 #include "wine/server.h"
32 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(win);
35 WINE_DECLARE_DEBUG_CHANNEL(keyboard);
37 static const WCHAR keyboard_layouts_keyW[] =
39 '\\','R','e','g','i','s','t','r','y',
40 '\\','M','a','c','h','i','n','e',
41 '\\','S','y','s','t','e','m',
42 '\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t',
43 '\\','C','o','n','t','r','o','l',
44 '\\','K','e','y','b','o','a','r','d',' ','L','a','y','o','u','t','s'
48 LONG global_key_state_counter = 0;
50 /**********************************************************************
51 * NtUserAttachThreadInput (win32u.@)
53 BOOL WINAPI NtUserAttachThreadInput( DWORD from, DWORD to, BOOL attach )
55 BOOL ret;
57 SERVER_START_REQ( attach_thread_input )
59 req->tid_from = from;
60 req->tid_to = to;
61 req->attach = attach;
62 ret = !wine_server_call_err( req );
64 SERVER_END_REQ;
65 return ret;
68 /***********************************************************************
69 * NtUserSetCursorPos (win32u.@)
71 BOOL WINAPI NtUserSetCursorPos( INT x, INT y )
73 POINT pt = { x, y };
74 BOOL ret;
75 INT prev_x, prev_y, new_x, new_y;
76 UINT dpi;
78 if ((dpi = get_thread_dpi()))
80 HMONITOR monitor = monitor_from_point( pt, MONITOR_DEFAULTTOPRIMARY, get_thread_dpi() );
81 pt = map_dpi_point( pt, dpi, get_monitor_dpi( monitor ));
84 SERVER_START_REQ( set_cursor )
86 req->flags = SET_CURSOR_POS;
87 req->x = pt.x;
88 req->y = pt.y;
89 if ((ret = !wine_server_call( req )))
91 prev_x = reply->prev_x;
92 prev_y = reply->prev_y;
93 new_x = reply->new_x;
94 new_y = reply->new_y;
97 SERVER_END_REQ;
98 if (ret && (prev_x != new_x || prev_y != new_y)) user_driver->pSetCursorPos( new_x, new_y );
99 return ret;
102 /***********************************************************************
103 * get_cursor_pos
105 BOOL get_cursor_pos( POINT *pt )
107 BOOL ret;
108 DWORD last_change;
109 UINT dpi;
111 if (!pt) return FALSE;
113 SERVER_START_REQ( set_cursor )
115 if ((ret = !wine_server_call( req )))
117 pt->x = reply->new_x;
118 pt->y = reply->new_y;
119 last_change = reply->last_change;
122 SERVER_END_REQ;
124 /* query new position from graphics driver if we haven't updated recently */
125 if (ret && NtGetTickCount() - last_change > 100) ret = user_driver->pGetCursorPos( pt );
126 if (ret && (dpi = get_thread_dpi()))
128 HMONITOR monitor = monitor_from_point( *pt, MONITOR_DEFAULTTOPRIMARY, 0 );
129 *pt = map_dpi_point( *pt, get_monitor_dpi( monitor ), dpi );
131 return ret;
134 /***********************************************************************
135 * NtUserGetCursorInfo (win32u.@)
137 BOOL WINAPI NtUserGetCursorInfo( CURSORINFO *info )
139 BOOL ret;
141 if (!info) return FALSE;
143 SERVER_START_REQ( get_thread_input )
145 req->tid = 0;
146 if ((ret = !wine_server_call( req )))
148 info->hCursor = wine_server_ptr_handle( reply->cursor );
149 info->flags = reply->show_count >= 0 ? CURSOR_SHOWING : 0;
152 SERVER_END_REQ;
153 get_cursor_pos( &info->ptScreenPos );
154 return ret;
157 static void check_for_events( UINT flags )
159 if (user_driver->pMsgWaitForMultipleObjectsEx( 0, NULL, 0, flags, 0 ) == WAIT_TIMEOUT)
160 flush_window_surfaces( TRUE );
163 /**********************************************************************
164 * GetAsyncKeyState (win32u.@)
166 SHORT WINAPI NtUserGetAsyncKeyState( INT key )
168 struct user_key_state_info *key_state_info = get_user_thread_info()->key_state;
169 INT counter = global_key_state_counter;
170 BYTE prev_key_state;
171 SHORT ret;
173 if (key < 0 || key >= 256) return 0;
175 check_for_events( QS_INPUT );
177 if (key_state_info && !(key_state_info->state[key] & 0xc0) &&
178 key_state_info->counter == counter && NtGetTickCount() - key_state_info->time < 50)
180 /* use cached value */
181 return 0;
183 else if (!key_state_info)
185 key_state_info = calloc( 1, sizeof(*key_state_info) );
186 get_user_thread_info()->key_state = key_state_info;
189 ret = 0;
190 SERVER_START_REQ( get_key_state )
192 req->async = 1;
193 req->key = key;
194 if (key_state_info)
196 prev_key_state = key_state_info->state[key];
197 wine_server_set_reply( req, key_state_info->state, sizeof(key_state_info->state) );
199 if (!wine_server_call( req ))
201 if (reply->state & 0x40) ret |= 0x0001;
202 if (reply->state & 0x80) ret |= 0x8000;
203 if (key_state_info)
205 /* force refreshing the key state cache - some multithreaded programs
206 * (like Adobe Photoshop CS5) expect that changes to the async key state
207 * are also immediately available in other threads. */
208 if (prev_key_state != key_state_info->state[key])
209 counter = InterlockedIncrement( &global_key_state_counter );
211 key_state_info->time = NtGetTickCount();
212 key_state_info->counter = counter;
216 SERVER_END_REQ;
218 return ret;
221 /***********************************************************************
222 * NtUserGetQueueStatus (win32u.@)
224 DWORD WINAPI NtUserGetQueueStatus( UINT flags )
226 DWORD ret;
228 if (flags & ~(QS_ALLINPUT | QS_ALLPOSTMESSAGE | QS_SMRESULT))
230 SetLastError( ERROR_INVALID_FLAGS );
231 return 0;
234 check_for_events( flags );
236 SERVER_START_REQ( get_queue_status )
238 req->clear_bits = flags;
239 wine_server_call( req );
240 ret = MAKELONG( reply->changed_bits & flags, reply->wake_bits & flags );
242 SERVER_END_REQ;
243 return ret;
246 /***********************************************************************
247 * get_input_state
249 DWORD get_input_state(void)
251 DWORD ret;
253 check_for_events( QS_INPUT );
255 SERVER_START_REQ( get_queue_status )
257 req->clear_bits = 0;
258 wine_server_call( req );
259 ret = reply->wake_bits & (QS_KEY | QS_MOUSEBUTTON);
261 SERVER_END_REQ;
262 return ret;
265 /***********************************************************************
266 * get_locale_kbd_layout
268 static HKL get_locale_kbd_layout(void)
270 LCID layout;
271 LANGID langid;
273 /* FIXME:
275 * layout = main_key_tab[kbd_layout].lcid;
277 * Winword uses return value of GetKeyboardLayout as a codepage
278 * to translate ANSI keyboard messages to unicode. But we have
279 * a problem with it: for instance Polish keyboard layout is
280 * identical to the US one, and therefore instead of the Polish
281 * locale id we return the US one.
284 NtQueryDefaultLocale( TRUE, &layout );
287 * Microsoft Office expects this value to be something specific
288 * for Japanese and Korean Windows with an IME the value is 0xe001
289 * We should probably check to see if an IME exists and if so then
290 * set this word properly.
292 langid = PRIMARYLANGID( LANGIDFROMLCID( layout ) );
293 if (langid == LANG_CHINESE || langid == LANG_JAPANESE || langid == LANG_KOREAN)
294 layout = MAKELONG( layout, 0xe001 ); /* IME */
295 else
296 layout = MAKELONG( layout, layout );
298 return ULongToHandle( layout );
301 /***********************************************************************
302 * NtUserGetKeyboardLayout (win32u.@)
304 * Device handle for keyboard layout defaulted to
305 * the language id. This is the way Windows default works.
307 HKL WINAPI NtUserGetKeyboardLayout( DWORD thread_id )
309 struct user_thread_info *thread = get_user_thread_info();
310 HKL layout = thread->kbd_layout;
312 if (thread_id && thread_id != GetCurrentThreadId())
313 FIXME( "couldn't return keyboard layout for thread %04x\n", thread_id );
315 if (!layout) return get_locale_kbd_layout();
316 return layout;
319 /**********************************************************************
320 * NtUserGetKeyState (win32u.@)
322 * An application calls the GetKeyState function in response to a
323 * keyboard-input message. This function retrieves the state of the key
324 * at the time the input message was generated.
326 SHORT WINAPI NtUserGetKeyState( INT vkey )
328 SHORT retval = 0;
330 SERVER_START_REQ( get_key_state )
332 req->key = vkey;
333 if (!wine_server_call( req )) retval = (signed char)(reply->state & 0x81);
335 SERVER_END_REQ;
336 TRACE("key (0x%x) -> %x\n", vkey, retval);
337 return retval;
340 /**********************************************************************
341 * NtUserGetKeyboardState (win32u.@)
343 BOOL WINAPI NtUserGetKeyboardState( BYTE *state )
345 BOOL ret;
346 UINT i;
348 TRACE("(%p)\n", state);
350 memset( state, 0, 256 );
351 SERVER_START_REQ( get_key_state )
353 req->key = -1;
354 wine_server_set_reply( req, state, 256 );
355 ret = !wine_server_call_err( req );
356 for (i = 0; i < 256; i++) state[i] &= 0x81;
358 SERVER_END_REQ;
359 return ret;
362 /**********************************************************************
363 * NtUserSetKeyboardState (win32u.@)
365 BOOL WINAPI NtUserSetKeyboardState( BYTE *state )
367 BOOL ret;
369 SERVER_START_REQ( set_key_state )
371 wine_server_add_data( req, state, 256 );
372 ret = !wine_server_call_err( req );
374 SERVER_END_REQ;
375 return ret;
378 /******************************************************************************
379 * NtUserVkKeyScanEx (win32u.@)
381 WORD WINAPI NtUserVkKeyScanEx( WCHAR chr, HKL layout )
383 WORD shift = 0x100, ctrl = 0x200;
384 SHORT ret;
386 TRACE_(keyboard)( "chr %s, layout %p\n", debugstr_wn(&chr, 1), layout );
388 if ((ret = user_driver->pVkKeyScanEx( chr, layout )) != -256) return ret;
390 /* FIXME: English keyboard layout specific */
392 if (chr == VK_CANCEL || chr == VK_BACK || chr == VK_TAB || chr == VK_RETURN ||
393 chr == VK_ESCAPE || chr == VK_SPACE) ret = chr;
394 else if (chr >= '0' && chr <= '9') ret = chr;
395 else if (chr == ')') ret = shift + '0';
396 else if (chr == '!') ret = shift + '1';
397 else if (chr == '@') ret = shift + '2';
398 else if (chr == '#') ret = shift + '3';
399 else if (chr == '$') ret = shift + '4';
400 else if (chr == '%') ret = shift + '5';
401 else if (chr == '^') ret = shift + '6';
402 else if (chr == '&') ret = shift + '7';
403 else if (chr == '*') ret = shift + '8';
404 else if (chr == '(') ret = shift + '9';
405 else if (chr >= 'a' && chr <= 'z') ret = chr - 'a' + 'A';
406 else if (chr >= 'A' && chr <= 'Z') ret = shift + chr;
407 else if (chr == ';') ret = VK_OEM_1;
408 else if (chr == '=') ret = VK_OEM_PLUS;
409 else if (chr == ',') ret = VK_OEM_COMMA;
410 else if (chr == '-') ret = VK_OEM_MINUS;
411 else if (chr == '.') ret = VK_OEM_PERIOD;
412 else if (chr == '/') ret = VK_OEM_2;
413 else if (chr == '`') ret = VK_OEM_3;
414 else if (chr == '[') ret = VK_OEM_4;
415 else if (chr == '\\') ret = VK_OEM_5;
416 else if (chr == ']') ret = VK_OEM_6;
417 else if (chr == '\'') ret = VK_OEM_7;
418 else if (chr == ':') ret = shift + VK_OEM_1;
419 else if (chr == '+') ret = shift + VK_OEM_PLUS;
420 else if (chr == '<') ret = shift + VK_OEM_COMMA;
421 else if (chr == '_') ret = shift + VK_OEM_MINUS;
422 else if (chr == '>') ret = shift + VK_OEM_PERIOD;
423 else if (chr == '?') ret = shift + VK_OEM_2;
424 else if (chr == '~') ret = shift + VK_OEM_3;
425 else if (chr == '{') ret = shift + VK_OEM_4;
426 else if (chr == '|') ret = shift + VK_OEM_5;
427 else if (chr == '}') ret = shift + VK_OEM_6;
428 else if (chr == '\"') ret = shift + VK_OEM_7;
429 else if (chr == 0x7f) ret = ctrl + VK_BACK;
430 else if (chr == '\n') ret = ctrl + VK_RETURN;
431 else if (chr == 0xf000) ret = ctrl + '2';
432 else if (chr == 0x0000) ret = ctrl + shift + '2';
433 else if (chr >= 0x0001 && chr <= 0x001a) ret = ctrl + 'A' + chr - 1;
434 else if (chr >= 0x001c && chr <= 0x001d) ret = ctrl + VK_OEM_3 + chr;
435 else if (chr == 0x001e) ret = ctrl + shift + '6';
436 else if (chr == 0x001f) ret = ctrl + shift + VK_OEM_MINUS;
437 else ret = -1;
439 TRACE_(keyboard)( "ret %04x\n", ret );
440 return ret;
443 /* English keyboard layout (0x0409) */
444 static const UINT kbd_en_vsc2vk[] =
446 0x00, 0x1b, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0xbd, 0xbb, 0x08, 0x09,
447 0x51, 0x57, 0x45, 0x52, 0x54, 0x59, 0x55, 0x49, 0x4f, 0x50, 0xdb, 0xdd, 0x0d, 0xa2, 0x41, 0x53,
448 0x44, 0x46, 0x47, 0x48, 0x4a, 0x4b, 0x4c, 0xba, 0xde, 0xc0, 0xa0, 0xdc, 0x5a, 0x58, 0x43, 0x56,
449 0x42, 0x4e, 0x4d, 0xbc, 0xbe, 0xbf, 0xa1, 0x6a, 0xa4, 0x20, 0x14, 0x70, 0x71, 0x72, 0x73, 0x74,
450 0x75, 0x76, 0x77, 0x78, 0x79, 0x90, 0x91, 0x24, 0x26, 0x21, 0x6d, 0x25, 0x0c, 0x27, 0x6b, 0x23,
451 0x28, 0x22, 0x2d, 0x2e, 0x2c, 0x00, 0xe2, 0x7a, 0x7b, 0x0c, 0xee, 0xf1, 0xea, 0xf9, 0xf5, 0xf3,
452 0x00, 0x00, 0xfb, 0x2f, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0xed,
453 0x00, 0xe9, 0x00, 0xc1, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, 0x00, 0xeb, 0x09, 0x00, 0xc2, 0x00,
454 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
455 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
456 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
457 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
458 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
459 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
460 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
461 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
462 /* 0xe000 */
463 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
464 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x0d, 0xa3, 0x00, 0x00,
465 0xad, 0xb7, 0xb3, 0x00, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xae, 0x00,
466 0xaf, 0x00, 0xac, 0x00, 0x00, 0x6f, 0x00, 0x2c, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
467 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x24, 0x26, 0x21, 0x00, 0x25, 0x00, 0x27, 0x00, 0x23,
468 0x28, 0x22, 0x2d, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5b, 0x5c, 0x5d, 0x00, 0x5f,
469 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xab, 0xa8, 0xa9, 0xa7, 0xa6, 0xb6, 0xb4, 0xb5, 0x00, 0x00,
470 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
471 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
472 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
473 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
474 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
475 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
476 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
477 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
478 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
479 /* 0xe100 */
480 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
481 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00,
482 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
483 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
484 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
485 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
486 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
487 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
488 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
489 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
490 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
491 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
492 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
493 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
494 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
495 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
498 static const UINT kbd_en_vk2char[] =
500 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x08, 0x09, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00,
501 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00,
502 ' ', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
503 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
504 0x00, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
505 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 0x00, 0x00, 0x00, 0x00, 0x00,
506 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '*', '+', 0x00, '-', '.', '/',
507 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
508 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
509 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
510 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
511 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ';', '=', ',', '-', '.', '/',
512 '`', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
513 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, '[', '\\', ']', '\'', 0x00,
514 0x00, 0x00, '\\', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
515 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
518 static const char *kbd_en_vscname[] =
520 0, "Esc", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Backspace", "Tab",
521 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Enter", "Ctrl", 0, 0,
522 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Shift", 0, 0, 0, 0, 0,
523 0, 0, 0, 0, 0, 0, "Right Shift", "Num *", "Alt", "Space", "Caps Lock", "F1", "F2", "F3", "F4", "F5",
524 "F6", "F7", "F8", "F9", "F10", "Pause", "Scroll Lock", "Num 7", "Num 8", "Num 9", "Num -", "Num 4", "Num 5", "Num 6", "Num +", "Num 1",
525 "Num 2", "Num 3", "Num 0", "Num Del", "Sys Req", 0, 0, "F11", "F12", 0, 0, 0, 0, 0, 0, 0,
526 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
527 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "F13", "F14", "F15", "F16",
528 "F17", "F18", "F19", "F20", "F21", "F22", "F23", "F24", 0, 0, 0, 0, 0, 0, 0, 0,
529 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
530 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
531 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
532 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
533 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
534 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
535 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
536 /* extended */
537 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
538 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Num Enter", "Right Ctrl", 0, 0,
539 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
540 0, 0, 0, 0, 0, "Num /", 0, "Prnt Scrn", "Right Alt", 0, 0, 0, 0, 0, 0, 0,
541 0, 0, 0, 0, 0, "Num Lock", "Break", "Home", "Up", "Page Up", 0, "Left", 0, "Right", 0, "End",
542 "Down", "Page Down", "Insert", "Delete", "<00>", 0, "Help", 0, 0, 0, 0, "Left Windows", "Right Windows", "Application", 0, 0,
543 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
544 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
545 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
546 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
547 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
548 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
549 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
550 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
551 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
552 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
555 /******************************************************************************
556 * NtUserMapVirtualKeyEx (win32u.@)
558 UINT WINAPI NtUserMapVirtualKeyEx( UINT code, UINT type, HKL layout )
560 const UINT *vsc2vk, *vk2char;
561 UINT vsc2vk_size, vk2char_size;
562 UINT ret;
564 TRACE_(keyboard)( "code %u, type %u, layout %p.\n", code, type, layout );
566 if ((ret = user_driver->pMapVirtualKeyEx( code, type, layout )) != -1) return ret;
568 /* FIXME: English keyboard layout specific */
570 vsc2vk = kbd_en_vsc2vk;
571 vsc2vk_size = ARRAYSIZE(kbd_en_vsc2vk);
572 vk2char = kbd_en_vk2char;
573 vk2char_size = ARRAYSIZE(kbd_en_vk2char);
575 switch (type)
577 case MAPVK_VK_TO_VSC_EX:
578 case MAPVK_VK_TO_VSC:
579 switch (code)
581 case VK_SHIFT: code = VK_LSHIFT; break;
582 case VK_CONTROL: code = VK_LCONTROL; break;
583 case VK_MENU: code = VK_LMENU; break;
584 case VK_NUMPAD0: code = VK_INSERT; break;
585 case VK_NUMPAD1: code = VK_END; break;
586 case VK_NUMPAD2: code = VK_DOWN; break;
587 case VK_NUMPAD3: code = VK_NEXT; break;
588 case VK_NUMPAD4: code = VK_LEFT; break;
589 case VK_NUMPAD5: code = VK_CLEAR; break;
590 case VK_NUMPAD6: code = VK_RIGHT; break;
591 case VK_NUMPAD7: code = VK_HOME; break;
592 case VK_NUMPAD8: code = VK_UP; break;
593 case VK_NUMPAD9: code = VK_PRIOR; break;
594 case VK_DECIMAL: code = VK_DELETE; break;
597 for (ret = 0; ret < vsc2vk_size; ++ret) if (vsc2vk[ret] == code) break;
598 if (ret >= vsc2vk_size) ret = 0;
600 if (type == MAPVK_VK_TO_VSC)
602 if (ret >= 0x200) ret = 0;
603 else ret &= 0xff;
605 else if (ret >= 0x100) ret += 0xdf00;
606 break;
607 case MAPVK_VSC_TO_VK:
608 case MAPVK_VSC_TO_VK_EX:
609 if (code & 0xe000) code -= 0xdf00;
610 if (code >= vsc2vk_size) ret = 0;
611 else ret = vsc2vk[code];
613 if (type == MAPVK_VSC_TO_VK)
615 switch (ret)
617 case VK_LSHIFT: case VK_RSHIFT: ret = VK_SHIFT; break;
618 case VK_LCONTROL: case VK_RCONTROL: ret = VK_CONTROL; break;
619 case VK_LMENU: case VK_RMENU: ret = VK_MENU; break;
622 break;
623 case MAPVK_VK_TO_CHAR:
624 if (code >= vk2char_size) ret = 0;
625 else ret = vk2char[code];
626 break;
627 default:
628 FIXME_(keyboard)( "unknown type %d\n", type );
629 return 0;
632 TRACE_(keyboard)( "returning 0x%04x\n", ret );
633 return ret;
636 /****************************************************************************
637 * NtUserGetKeyNameText (win32u.@)
639 INT WINAPI NtUserGetKeyNameText( LONG lparam, WCHAR *buffer, INT size )
641 INT code = ((lparam >> 16) & 0x1ff), vkey, len;
642 UINT vsc2vk_size, vscname_size;
643 const char *const *vscname;
644 const UINT *vsc2vk;
646 TRACE_(keyboard)( "lparam %d, buffer %p, size %d.\n", lparam, buffer, size );
648 if (!buffer || !size) return 0;
649 if ((len = user_driver->pGetKeyNameText( lparam, buffer, size )) >= 0) return len;
651 /* FIXME: English keyboard layout specific */
653 vsc2vk = kbd_en_vsc2vk;
654 vsc2vk_size = ARRAYSIZE(kbd_en_vsc2vk);
655 vscname = kbd_en_vscname;
656 vscname_size = ARRAYSIZE(kbd_en_vscname);
658 if (lparam & 0x2000000)
660 switch ((vkey = vsc2vk[code]))
662 case VK_RSHIFT:
663 case VK_RCONTROL:
664 case VK_RMENU:
665 for (code = 0; code < vsc2vk_size; ++code)
666 if (vsc2vk[code] == (vkey - 1)) break;
667 break;
671 if (code < vscname_size)
673 if (vscname[code])
675 len = min( size - 1, strlen(vscname[code]) );
676 ascii_to_unicode( buffer, vscname[code], len );
678 else if (size > 1)
680 HKL hkl = NtUserGetKeyboardLayout( 0 );
681 vkey = NtUserMapVirtualKeyEx( code & 0xff, MAPVK_VSC_TO_VK, hkl );
682 buffer[0] = NtUserMapVirtualKeyEx( vkey, MAPVK_VK_TO_CHAR, hkl );
683 len = 1;
686 buffer[len] = 0;
688 TRACE_(keyboard)( "ret %d, str %s.\n", len, debugstr_w(buffer) );
689 return len;
692 /****************************************************************************
693 * NtUserToUnicodeEx (win32u.@)
695 INT WINAPI NtUserToUnicodeEx( UINT virt, UINT scan, const BYTE *state,
696 WCHAR *str, int size, UINT flags, HKL layout )
698 BOOL shift, ctrl, alt, numlock;
699 WCHAR buffer[2];
700 INT len;
702 TRACE_(keyboard)( "virt %u, scan %u, state %p, str %p, size %d, flags %x, layout %p.\n",
703 virt, scan, state, str, size, flags, layout );
705 if (!state) return 0;
706 if ((len = user_driver->pToUnicodeEx( virt, scan, state, str, size, flags, layout )) >= -1)
707 return len;
709 alt = state[VK_MENU] & 0x80;
710 shift = state[VK_SHIFT] & 0x80;
711 ctrl = state[VK_CONTROL] & 0x80;
712 numlock = state[VK_NUMLOCK] & 0x01;
714 /* FIXME: English keyboard layout specific */
716 if (scan & 0x8000) buffer[0] = 0; /* key up */
717 else if (virt == VK_ESCAPE) buffer[0] = VK_ESCAPE;
718 else if (!ctrl)
720 switch (virt)
722 case VK_BACK: buffer[0] = '\b'; break;
723 case VK_OEM_1: buffer[0] = shift ? ':' : ';'; break;
724 case VK_OEM_2: buffer[0] = shift ? '?' : '/'; break;
725 case VK_OEM_3: buffer[0] = shift ? '~' : '`'; break;
726 case VK_OEM_4: buffer[0] = shift ? '{' : '['; break;
727 case VK_OEM_5: buffer[0] = shift ? '|' : '\\'; break;
728 case VK_OEM_6: buffer[0] = shift ? '}' : ']'; break;
729 case VK_OEM_7: buffer[0] = shift ? '"' : '\''; break;
730 case VK_OEM_COMMA: buffer[0] = shift ? '<' : ','; break;
731 case VK_OEM_MINUS: buffer[0] = shift ? '_' : '-'; break;
732 case VK_OEM_PERIOD: buffer[0] = shift ? '>' : '.'; break;
733 case VK_OEM_PLUS: buffer[0] = shift ? '+' : '='; break;
734 case VK_RETURN: buffer[0] = '\r'; break;
735 case VK_SPACE: buffer[0] = ' '; break;
736 case VK_TAB: buffer[0] = '\t'; break;
737 case VK_MULTIPLY: buffer[0] = '*'; break;
738 case VK_ADD: buffer[0] = '+'; break;
739 case VK_SUBTRACT: buffer[0] = '-'; break;
740 case VK_DIVIDE: buffer[0] = '/'; break;
741 default:
742 if (virt >= '0' && virt <= '9')
743 buffer[0] = shift ? ")!@#$%^&*("[virt - '0'] : virt;
744 else if (virt >= 'A' && virt <= 'Z')
745 buffer[0] = shift || (state[VK_CAPITAL] & 0x01) ? virt : virt + 'a' - 'A';
746 else if (virt >= VK_NUMPAD0 && virt <= VK_NUMPAD9 && numlock && !shift)
747 buffer[0] = '0' + virt - VK_NUMPAD0;
748 else if (virt == VK_DECIMAL && numlock && !shift)
749 buffer[0] = '.';
750 else
751 buffer[0] = 0;
752 break;
755 else if (!alt) /* Control codes */
757 switch (virt)
759 case VK_OEM_4: buffer[0] = 0x1b; break;
760 case VK_OEM_5: buffer[0] = 0x1c; break;
761 case VK_OEM_6: buffer[0] = 0x1d; break;
762 case '6': buffer[0] = shift ? 0x1e : 0; break;
763 case VK_OEM_MINUS: buffer[0] = shift ? 0x1f : 0; break;
764 case VK_BACK: buffer[0] = 0x7f; break;
765 case VK_RETURN: buffer[0] = shift ? 0 : '\n'; break;
766 case '2': buffer[0] = shift ? 0xffff : 0xf000; break;
767 case VK_SPACE: buffer[0] = ' '; break;
768 default:
769 if (virt >= 'A' && virt <= 'Z') buffer[0] = virt - 'A' + 1;
770 else buffer[0] = 0;
771 break;
774 else buffer[0] = 0;
775 buffer[1] = 0;
776 len = lstrlenW( buffer );
777 if (buffer[0] == 0xffff) buffer[0] = 0;
778 lstrcpynW( str, buffer, size );
780 TRACE_(keyboard)( "ret %d, str %s.\n", len, debugstr_w(str) );
781 return len;
784 /**********************************************************************
785 * NtUserActivateKeyboardLayout (win32u.@)
787 HKL WINAPI NtUserActivateKeyboardLayout( HKL layout, UINT flags )
789 struct user_thread_info *info = get_user_thread_info();
790 HKL old_layout;
792 TRACE_(keyboard)( "layout %p, flags %x\n", layout, flags );
794 if (flags) FIXME_(keyboard)( "flags %x not supported\n", flags );
796 if (layout == (HKL)HKL_NEXT || layout == (HKL)HKL_PREV)
798 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
799 FIXME_(keyboard)( "HKL_NEXT and HKL_PREV not supported\n" );
800 return 0;
803 if (!user_driver->pActivateKeyboardLayout( layout, flags ))
804 return 0;
806 old_layout = info->kbd_layout;
807 info->kbd_layout = layout;
808 if (old_layout != layout) info->kbd_layout_id = 0;
810 if (!old_layout) return get_locale_kbd_layout();
811 return old_layout;
816 /***********************************************************************
817 * NtUserGetKeyboardLayoutList (win32u.@)
819 * Return number of values available if either input parm is
820 * 0, per MS documentation.
822 UINT WINAPI NtUserGetKeyboardLayoutList( INT size, HKL *layouts )
824 char buffer[4096];
825 KEY_NODE_INFORMATION *key_info = (KEY_NODE_INFORMATION *)buffer;
826 KEY_VALUE_PARTIAL_INFORMATION *value_info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
827 DWORD count, tmp, i = 0;
828 HKEY hkey, subkey;
829 HKL layout;
831 TRACE_(keyboard)( "size %d, layouts %p.\n", size, layouts );
833 if ((count = user_driver->pGetKeyboardLayoutList( size, layouts )) != ~0) return count;
835 layout = get_locale_kbd_layout();
836 count = 0;
838 count++;
839 if (size && layouts)
841 layouts[count - 1] = layout;
842 if (count == size) return count;
845 if ((hkey = reg_open_key( NULL, keyboard_layouts_keyW, sizeof(keyboard_layouts_keyW) )))
847 while (!NtEnumerateKey( hkey, i++, KeyNodeInformation, key_info,
848 sizeof(buffer) - sizeof(WCHAR), &tmp ))
850 if (!(subkey = reg_open_key( hkey, key_info->Name, key_info->NameLength ))) continue;
851 key_info->Name[key_info->NameLength / sizeof(WCHAR)] = 0;
852 tmp = wcstoul( key_info->Name, NULL, 16 );
853 if (query_reg_ascii_value( subkey, "Layout Id", value_info, sizeof(buffer) ) &&
854 value_info->Type == REG_SZ)
855 tmp = MAKELONG( LOWORD( tmp ),
856 0xf000 | (wcstoul( (const WCHAR *)value_info->Data, NULL, 16 ) & 0xfff) );
857 NtClose( subkey );
859 if (layout == UlongToHandle( tmp )) continue;
861 count++;
862 if (size && layouts)
864 layouts[count - 1] = UlongToHandle( tmp );
865 if (count == size) break;
868 NtClose( hkey );
871 return count;
874 /****************************************************************************
875 * NtUserGetKeyboardLayoutName (win32u.@)
877 BOOL WINAPI NtUserGetKeyboardLayoutName( WCHAR *name )
879 struct user_thread_info *info = get_user_thread_info();
880 char buffer[4096];
881 KEY_NODE_INFORMATION *key = (KEY_NODE_INFORMATION *)buffer;
882 KEY_VALUE_PARTIAL_INFORMATION *value = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
883 WCHAR klid[KL_NAMELENGTH];
884 DWORD tmp, i = 0;
885 HKEY hkey, subkey;
886 HKL layout;
888 TRACE_(keyboard)( "name %p\n", name );
890 if (!name)
892 SetLastError( ERROR_NOACCESS );
893 return FALSE;
896 if (info->kbd_layout_id)
898 sprintf( buffer, "%08X", info->kbd_layout_id );
899 asciiz_to_unicode( name, buffer );
900 return TRUE;
903 layout = NtUserGetKeyboardLayout( 0 );
904 tmp = HandleToUlong( layout );
905 if (HIWORD( tmp ) == LOWORD( tmp )) tmp = LOWORD( tmp );
906 sprintf( buffer, "%08X", tmp );
907 asciiz_to_unicode( name, buffer );
909 if ((hkey = reg_open_key( NULL, keyboard_layouts_keyW, sizeof(keyboard_layouts_keyW) )))
911 while (!NtEnumerateKey( hkey, i++, KeyNodeInformation, key,
912 sizeof(buffer) - sizeof(WCHAR), &tmp ))
914 if (!(subkey = reg_open_key( hkey, key->Name, key->NameLength ))) continue;
915 memcpy( klid, key->Name, key->NameLength );
916 klid[key->NameLength / sizeof(WCHAR)] = 0;
917 if (query_reg_ascii_value( subkey, "Layout Id", value, sizeof(buffer) ) &&
918 value->Type == REG_SZ)
919 tmp = 0xf000 | (wcstoul( (const WCHAR *)value->Data, NULL, 16 ) & 0xfff);
920 else
921 tmp = wcstoul( klid, NULL, 16 );
922 NtClose( subkey );
924 if (HIWORD( layout ) == tmp)
926 lstrcpynW( name, klid, KL_NAMELENGTH );
927 break;
930 NtClose( hkey );
933 info->kbd_layout_id = wcstoul( name, NULL, 16 );
935 TRACE_(keyboard)( "ret %s\n", debugstr_w( name ) );
936 return TRUE;
939 /***********************************************************************
940 * NtUserRegisterHotKey (win32u.@)
942 BOOL WINAPI NtUserRegisterHotKey( HWND hwnd, INT id, UINT modifiers, UINT vk )
944 BOOL ret;
945 int replaced = 0;
947 TRACE_(keyboard)( "(%p,%d,0x%08x,%X)\n", hwnd, id, modifiers, vk );
949 if ((!hwnd || is_current_thread_window( hwnd )) &&
950 !user_driver->pRegisterHotKey( hwnd, modifiers, vk ))
951 return FALSE;
953 SERVER_START_REQ( register_hotkey )
955 req->window = wine_server_user_handle( hwnd );
956 req->id = id;
957 req->flags = modifiers;
958 req->vkey = vk;
959 if ((ret = !wine_server_call_err( req )))
961 replaced = reply->replaced;
962 modifiers = reply->flags;
963 vk = reply->vkey;
966 SERVER_END_REQ;
968 if (ret && replaced)
969 user_driver->pUnregisterHotKey(hwnd, modifiers, vk);
971 return ret;
974 /***********************************************************************
975 * NtUserUnregisterHotKey (win32u.@)
977 BOOL WINAPI NtUserUnregisterHotKey( HWND hwnd, INT id )
979 BOOL ret;
980 UINT modifiers, vk;
982 TRACE_(keyboard)("(%p,%d)\n",hwnd,id);
984 SERVER_START_REQ( unregister_hotkey )
986 req->window = wine_server_user_handle( hwnd );
987 req->id = id;
988 if ((ret = !wine_server_call_err( req )))
990 modifiers = reply->flags;
991 vk = reply->vkey;
994 SERVER_END_REQ;
996 if (ret)
997 user_driver->pUnregisterHotKey(hwnd, modifiers, vk);
999 return ret;
1002 /***********************************************************************
1003 * NtUserGetMouseMovePointsEx (win32u.@)
1005 int WINAPI NtUserGetMouseMovePointsEx( UINT size, MOUSEMOVEPOINT *ptin, MOUSEMOVEPOINT *ptout,
1006 int count, DWORD resolution )
1008 cursor_pos_t *pos, positions[64];
1009 int copied;
1010 unsigned int i;
1013 TRACE( "%d, %p, %p, %d, %d\n", size, ptin, ptout, count, resolution );
1015 if ((size != sizeof(MOUSEMOVEPOINT)) || (count < 0) || (count > ARRAY_SIZE( positions )))
1017 SetLastError( ERROR_INVALID_PARAMETER );
1018 return -1;
1021 if (!ptin || (!ptout && count))
1023 SetLastError( ERROR_NOACCESS );
1024 return -1;
1027 if (resolution != GMMP_USE_DISPLAY_POINTS)
1029 FIXME( "only GMMP_USE_DISPLAY_POINTS is supported for now\n" );
1030 SetLastError( ERROR_POINT_NOT_FOUND );
1031 return -1;
1034 SERVER_START_REQ( get_cursor_history )
1036 wine_server_set_reply( req, &positions, sizeof(positions) );
1037 if (wine_server_call_err( req )) return -1;
1039 SERVER_END_REQ;
1041 for (i = 0; i < ARRAY_SIZE( positions ); i++)
1043 pos = &positions[i];
1044 if (ptin->x == pos->x && ptin->y == pos->y && (!ptin->time || ptin->time == pos->time))
1045 break;
1048 if (i == ARRAY_SIZE( positions ))
1050 SetLastError( ERROR_POINT_NOT_FOUND );
1051 return -1;
1054 for (copied = 0; copied < count && i < ARRAY_SIZE( positions ); copied++, i++)
1056 pos = &positions[i];
1057 ptout[copied].x = pos->x;
1058 ptout[copied].y = pos->y;
1059 ptout[copied].time = pos->time;
1060 ptout[copied].dwExtraInfo = pos->info;
1063 return copied;
1066 /*******************************************************************
1067 * NtUserGetForegroundWindow (win32u.@)
1069 HWND WINAPI NtUserGetForegroundWindow(void)
1071 HWND ret = 0;
1073 SERVER_START_REQ( get_thread_input )
1075 req->tid = 0;
1076 if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->foreground );
1078 SERVER_END_REQ;
1079 return ret;
1082 /* see GetActiveWindow */
1083 HWND get_active_window(void)
1085 GUITHREADINFO info;
1086 info.cbSize = sizeof(info);
1087 return NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info ) ? info.hwndActive : 0;
1090 /* see GetFocus */
1091 static HWND get_focus(void)
1093 GUITHREADINFO info;
1094 info.cbSize = sizeof(info);
1095 return NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info ) ? info.hwndFocus : 0;
1098 /*****************************************************************
1099 * set_focus_window
1101 * Change the focus window, sending the WM_SETFOCUS and WM_KILLFOCUS messages
1103 static HWND set_focus_window( HWND hwnd )
1105 HWND previous = 0;
1106 BOOL ret;
1108 SERVER_START_REQ( set_focus_window )
1110 req->handle = wine_server_user_handle( hwnd );
1111 if ((ret = !wine_server_call_err( req )))
1112 previous = wine_server_ptr_handle( reply->previous );
1114 SERVER_END_REQ;
1115 if (!ret) return 0;
1116 if (previous == hwnd) return previous;
1118 if (previous)
1120 send_message( previous, WM_KILLFOCUS, (WPARAM)hwnd, 0 );
1122 if (user_callbacks) user_callbacks->notify_ime( previous, IME_INTERNAL_DEACTIVATE );
1124 if (hwnd != get_focus()) return previous; /* changed by the message */
1126 if (is_window(hwnd))
1128 user_driver->pSetFocus(hwnd);
1130 if (user_callbacks) user_callbacks->notify_ime( hwnd, IME_INTERNAL_ACTIVATE );
1132 if (previous)
1133 NtUserNotifyWinEvent( EVENT_OBJECT_FOCUS, hwnd, OBJID_CLIENT, 0 );
1135 send_message( hwnd, WM_SETFOCUS, (WPARAM)previous, 0 );
1137 return previous;
1140 /*******************************************************************
1141 * set_active_window
1143 static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus )
1145 HWND previous = get_active_window();
1146 BOOL ret;
1147 DWORD old_thread, new_thread;
1148 CBTACTIVATESTRUCT cbt;
1150 if (previous == hwnd)
1152 if (prev) *prev = hwnd;
1153 return TRUE;
1156 /* call CBT hook chain */
1157 cbt.fMouse = mouse;
1158 cbt.hWndActive = previous;
1159 if (call_hooks( WH_CBT, HCBT_ACTIVATE, (WPARAM)hwnd, (LPARAM)&cbt, TRUE )) return FALSE;
1161 if (is_window( previous ))
1163 send_message( previous, WM_NCACTIVATE, FALSE, (LPARAM)hwnd );
1164 send_message( previous, WM_ACTIVATE,
1165 MAKEWPARAM( WA_INACTIVE, is_iconic(previous) ), (LPARAM)hwnd );
1168 SERVER_START_REQ( set_active_window )
1170 req->handle = wine_server_user_handle( hwnd );
1171 if ((ret = !wine_server_call_err( req )))
1172 previous = wine_server_ptr_handle( reply->previous );
1174 SERVER_END_REQ;
1175 if (!ret) return FALSE;
1176 if (prev) *prev = previous;
1177 if (previous == hwnd) return TRUE;
1179 if (hwnd)
1181 /* send palette messages */
1182 if (send_message( hwnd, WM_QUERYNEWPALETTE, 0, 0 ) && user_callbacks)
1183 user_callbacks->pSendMessageTimeoutW( HWND_BROADCAST, WM_PALETTEISCHANGING, (WPARAM)hwnd, 0,
1184 SMTO_ABORTIFHUNG, 2000, NULL );
1185 if (!is_window(hwnd)) return FALSE;
1188 old_thread = previous ? get_window_thread( previous, NULL ) : 0;
1189 new_thread = hwnd ? get_window_thread( hwnd, NULL ) : 0;
1191 if (old_thread != new_thread)
1193 HWND *list, *phwnd;
1195 if ((list = list_window_children( NULL, get_desktop_window(), NULL, 0 )))
1197 if (old_thread)
1199 for (phwnd = list; *phwnd; phwnd++)
1201 if (get_window_thread( *phwnd, NULL ) == old_thread)
1202 send_message( *phwnd, WM_ACTIVATEAPP, 0, new_thread );
1205 if (new_thread)
1207 for (phwnd = list; *phwnd; phwnd++)
1209 if (get_window_thread( *phwnd, NULL ) == new_thread)
1210 send_message( *phwnd, WM_ACTIVATEAPP, 1, old_thread );
1213 free( list );
1217 if (is_window(hwnd))
1219 send_message( hwnd, WM_NCACTIVATE, hwnd == NtUserGetForegroundWindow(), (LPARAM)previous );
1220 send_message( hwnd, WM_ACTIVATE,
1221 MAKEWPARAM( mouse ? WA_CLICKACTIVE : WA_ACTIVE, is_iconic(hwnd) ),
1222 (LPARAM)previous );
1223 if (NtUserGetAncestor( hwnd, GA_PARENT ) == get_desktop_window())
1224 post_message( get_desktop_window(), WM_PARENTNOTIFY, WM_NCACTIVATE, (LPARAM)hwnd );
1227 /* now change focus if necessary */
1228 if (focus)
1230 GUITHREADINFO info;
1232 info.cbSize = sizeof(info);
1233 NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info );
1234 /* Do not change focus if the window is no more active */
1235 if (hwnd == info.hwndActive)
1237 if (!info.hwndFocus || !hwnd || NtUserGetAncestor( info.hwndFocus, GA_ROOT ) != hwnd)
1238 set_focus_window( hwnd );
1242 return TRUE;
1245 /**********************************************************************
1246 * NtUserSetActiveWindow (win32u.@)
1248 HWND WINAPI NtUserSetActiveWindow( HWND hwnd )
1250 HWND prev;
1252 TRACE( "%p\n", hwnd );
1254 if (hwnd)
1256 LONG style;
1258 hwnd = get_full_window_handle( hwnd );
1259 if (!is_window( hwnd ))
1261 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1262 return 0;
1265 style = get_window_long( hwnd, GWL_STYLE );
1266 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD)
1267 return get_active_window(); /* Windows doesn't seem to return an error here */
1270 if (!set_active_window( hwnd, &prev, FALSE, TRUE )) return 0;
1271 return prev;
1274 /*****************************************************************
1275 * NtUserSetFocus (win32u.@)
1277 HWND WINAPI NtUserSetFocus( HWND hwnd )
1279 HWND hwndTop = hwnd;
1280 HWND previous = get_focus();
1282 TRACE( "%p prev %p\n", hwnd, previous );
1284 if (hwnd)
1286 /* Check if we can set the focus to this window */
1287 hwnd = get_full_window_handle( hwnd );
1288 if (!is_window( hwnd ))
1290 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1291 return 0;
1293 if (hwnd == previous) return previous; /* nothing to do */
1294 for (;;)
1296 HWND parent;
1297 LONG style = get_window_long( hwndTop, GWL_STYLE );
1298 if (style & (WS_MINIMIZE | WS_DISABLED)) return 0;
1299 if (!(style & WS_CHILD)) break;
1300 parent = NtUserGetAncestor( hwndTop, GA_PARENT );
1301 if (!parent || parent == get_desktop_window())
1303 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return 0;
1304 break;
1306 if (parent == get_hwnd_message_parent()) return 0;
1307 hwndTop = parent;
1310 /* call hooks */
1311 if (call_hooks( WH_CBT, HCBT_SETFOCUS, (WPARAM)hwnd, (LPARAM)previous, TRUE )) return 0;
1313 /* activate hwndTop if needed. */
1314 if (hwndTop != get_active_window())
1316 if (!set_active_window( hwndTop, NULL, FALSE, FALSE )) return 0;
1317 if (!is_window( hwnd )) return 0; /* Abort if window destroyed */
1319 /* Do not change focus if the window is no longer active */
1320 if (hwndTop != get_active_window()) return 0;
1323 else /* NULL hwnd passed in */
1325 if (!previous) return 0; /* nothing to do */
1326 if (call_hooks( WH_CBT, HCBT_SETFOCUS, 0, (LPARAM)previous, TRUE )) return 0;
1329 /* change focus and send messages */
1330 return set_focus_window( hwnd );
1333 /*******************************************************************
1334 * set_foreground_window
1336 BOOL set_foreground_window( HWND hwnd, BOOL mouse )
1338 BOOL ret, send_msg_old = FALSE, send_msg_new = FALSE;
1339 HWND previous = 0;
1341 if (mouse) hwnd = get_full_window_handle( hwnd );
1343 SERVER_START_REQ( set_foreground_window )
1345 req->handle = wine_server_user_handle( hwnd );
1346 if ((ret = !wine_server_call_err( req )))
1348 previous = wine_server_ptr_handle( reply->previous );
1349 send_msg_old = reply->send_msg_old;
1350 send_msg_new = reply->send_msg_new;
1353 SERVER_END_REQ;
1355 if (ret && previous != hwnd)
1357 if (send_msg_old) /* old window belongs to other thread */
1358 NtUserMessageCall( previous, WM_WINE_SETACTIVEWINDOW, 0, 0,
1359 0, FNID_SENDNOTIFYMESSAGE, FALSE );
1360 else if (send_msg_new) /* old window belongs to us but new one to other thread */
1361 ret = set_active_window( 0, NULL, mouse, TRUE );
1363 if (send_msg_new) /* new window belongs to other thread */
1364 NtUserMessageCall( hwnd, WM_WINE_SETACTIVEWINDOW, (WPARAM)hwnd, 0,
1365 0, FNID_SENDNOTIFYMESSAGE, FALSE );
1366 else /* new window belongs to us */
1367 ret = set_active_window( hwnd, NULL, mouse, TRUE );
1369 return ret;