win32u: Move reply_message_result implementation from user32.
[wine.git] / dlls / win32u / input.c
blob5cd2cdd09708007e5c7e1e2bde5e0ee20f1bbf41
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 * NtUserSendInput (win32u.@)
71 UINT WINAPI NtUserSendInput( UINT count, INPUT *inputs, int size )
73 if (!user_callbacks) return 0;
74 return user_callbacks->pSendInput( count, inputs, size );
77 /***********************************************************************
78 * NtUserSetCursorPos (win32u.@)
80 BOOL WINAPI NtUserSetCursorPos( INT x, INT y )
82 POINT pt = { x, y };
83 BOOL ret;
84 INT prev_x, prev_y, new_x, new_y;
85 UINT dpi;
87 if ((dpi = get_thread_dpi()))
89 HMONITOR monitor = monitor_from_point( pt, MONITOR_DEFAULTTOPRIMARY, get_thread_dpi() );
90 pt = map_dpi_point( pt, dpi, get_monitor_dpi( monitor ));
93 SERVER_START_REQ( set_cursor )
95 req->flags = SET_CURSOR_POS;
96 req->x = pt.x;
97 req->y = pt.y;
98 if ((ret = !wine_server_call( req )))
100 prev_x = reply->prev_x;
101 prev_y = reply->prev_y;
102 new_x = reply->new_x;
103 new_y = reply->new_y;
106 SERVER_END_REQ;
107 if (ret && (prev_x != new_x || prev_y != new_y)) user_driver->pSetCursorPos( new_x, new_y );
108 return ret;
111 /***********************************************************************
112 * get_cursor_pos
114 BOOL get_cursor_pos( POINT *pt )
116 BOOL ret;
117 DWORD last_change;
118 UINT dpi;
120 if (!pt) return FALSE;
122 SERVER_START_REQ( set_cursor )
124 if ((ret = !wine_server_call( req )))
126 pt->x = reply->new_x;
127 pt->y = reply->new_y;
128 last_change = reply->last_change;
131 SERVER_END_REQ;
133 /* query new position from graphics driver if we haven't updated recently */
134 if (ret && NtGetTickCount() - last_change > 100) ret = user_driver->pGetCursorPos( pt );
135 if (ret && (dpi = get_thread_dpi()))
137 HMONITOR monitor = monitor_from_point( *pt, MONITOR_DEFAULTTOPRIMARY, 0 );
138 *pt = map_dpi_point( *pt, get_monitor_dpi( monitor ), dpi );
140 return ret;
143 /***********************************************************************
144 * NtUserGetCursorInfo (win32u.@)
146 BOOL WINAPI NtUserGetCursorInfo( CURSORINFO *info )
148 BOOL ret;
150 if (!info) return FALSE;
152 SERVER_START_REQ( get_thread_input )
154 req->tid = 0;
155 if ((ret = !wine_server_call( req )))
157 info->hCursor = wine_server_ptr_handle( reply->cursor );
158 info->flags = reply->show_count >= 0 ? CURSOR_SHOWING : 0;
161 SERVER_END_REQ;
162 get_cursor_pos( &info->ptScreenPos );
163 return ret;
166 static void check_for_events( UINT flags )
168 if (user_driver->pMsgWaitForMultipleObjectsEx( 0, NULL, 0, flags, 0 ) == WAIT_TIMEOUT)
169 flush_window_surfaces( TRUE );
172 /**********************************************************************
173 * GetAsyncKeyState (win32u.@)
175 SHORT WINAPI NtUserGetAsyncKeyState( INT key )
177 struct user_key_state_info *key_state_info = get_user_thread_info()->key_state;
178 INT counter = global_key_state_counter;
179 BYTE prev_key_state;
180 SHORT ret;
182 if (key < 0 || key >= 256) return 0;
184 check_for_events( QS_INPUT );
186 if (key_state_info && !(key_state_info->state[key] & 0xc0) &&
187 key_state_info->counter == counter && NtGetTickCount() - key_state_info->time < 50)
189 /* use cached value */
190 return 0;
192 else if (!key_state_info)
194 key_state_info = calloc( 1, sizeof(*key_state_info) );
195 get_user_thread_info()->key_state = key_state_info;
198 ret = 0;
199 SERVER_START_REQ( get_key_state )
201 req->async = 1;
202 req->key = key;
203 if (key_state_info)
205 prev_key_state = key_state_info->state[key];
206 wine_server_set_reply( req, key_state_info->state, sizeof(key_state_info->state) );
208 if (!wine_server_call( req ))
210 if (reply->state & 0x40) ret |= 0x0001;
211 if (reply->state & 0x80) ret |= 0x8000;
212 if (key_state_info)
214 /* force refreshing the key state cache - some multithreaded programs
215 * (like Adobe Photoshop CS5) expect that changes to the async key state
216 * are also immediately available in other threads. */
217 if (prev_key_state != key_state_info->state[key])
218 counter = InterlockedIncrement( &global_key_state_counter );
220 key_state_info->time = NtGetTickCount();
221 key_state_info->counter = counter;
225 SERVER_END_REQ;
227 return ret;
230 /***********************************************************************
231 * NtUserGetQueueStatus (win32u.@)
233 DWORD WINAPI NtUserGetQueueStatus( UINT flags )
235 DWORD ret;
237 if (flags & ~(QS_ALLINPUT | QS_ALLPOSTMESSAGE | QS_SMRESULT))
239 SetLastError( ERROR_INVALID_FLAGS );
240 return 0;
243 check_for_events( flags );
245 SERVER_START_REQ( get_queue_status )
247 req->clear_bits = flags;
248 wine_server_call( req );
249 ret = MAKELONG( reply->changed_bits & flags, reply->wake_bits & flags );
251 SERVER_END_REQ;
252 return ret;
255 /***********************************************************************
256 * get_input_state
258 DWORD get_input_state(void)
260 DWORD ret;
262 check_for_events( QS_INPUT );
264 SERVER_START_REQ( get_queue_status )
266 req->clear_bits = 0;
267 wine_server_call( req );
268 ret = reply->wake_bits & (QS_KEY | QS_MOUSEBUTTON);
270 SERVER_END_REQ;
271 return ret;
274 /***********************************************************************
275 * get_locale_kbd_layout
277 static HKL get_locale_kbd_layout(void)
279 LCID layout;
280 LANGID langid;
282 /* FIXME:
284 * layout = main_key_tab[kbd_layout].lcid;
286 * Winword uses return value of GetKeyboardLayout as a codepage
287 * to translate ANSI keyboard messages to unicode. But we have
288 * a problem with it: for instance Polish keyboard layout is
289 * identical to the US one, and therefore instead of the Polish
290 * locale id we return the US one.
293 NtQueryDefaultLocale( TRUE, &layout );
296 * Microsoft Office expects this value to be something specific
297 * for Japanese and Korean Windows with an IME the value is 0xe001
298 * We should probably check to see if an IME exists and if so then
299 * set this word properly.
301 langid = PRIMARYLANGID( LANGIDFROMLCID( layout ) );
302 if (langid == LANG_CHINESE || langid == LANG_JAPANESE || langid == LANG_KOREAN)
303 layout = MAKELONG( layout, 0xe001 ); /* IME */
304 else
305 layout = MAKELONG( layout, layout );
307 return ULongToHandle( layout );
310 /***********************************************************************
311 * NtUserGetKeyboardLayout (win32u.@)
313 * Device handle for keyboard layout defaulted to
314 * the language id. This is the way Windows default works.
316 HKL WINAPI NtUserGetKeyboardLayout( DWORD thread_id )
318 struct user_thread_info *thread = get_user_thread_info();
319 HKL layout = thread->kbd_layout;
321 if (thread_id && thread_id != GetCurrentThreadId())
322 FIXME( "couldn't return keyboard layout for thread %04x\n", thread_id );
324 if (!layout) return get_locale_kbd_layout();
325 return layout;
328 /**********************************************************************
329 * NtUserGetKeyState (win32u.@)
331 * An application calls the GetKeyState function in response to a
332 * keyboard-input message. This function retrieves the state of the key
333 * at the time the input message was generated.
335 SHORT WINAPI NtUserGetKeyState( INT vkey )
337 SHORT retval = 0;
339 SERVER_START_REQ( get_key_state )
341 req->key = vkey;
342 if (!wine_server_call( req )) retval = (signed char)(reply->state & 0x81);
344 SERVER_END_REQ;
345 TRACE("key (0x%x) -> %x\n", vkey, retval);
346 return retval;
349 /**********************************************************************
350 * NtUserGetKeyboardState (win32u.@)
352 BOOL WINAPI NtUserGetKeyboardState( BYTE *state )
354 BOOL ret;
355 UINT i;
357 TRACE("(%p)\n", state);
359 memset( state, 0, 256 );
360 SERVER_START_REQ( get_key_state )
362 req->key = -1;
363 wine_server_set_reply( req, state, 256 );
364 ret = !wine_server_call_err( req );
365 for (i = 0; i < 256; i++) state[i] &= 0x81;
367 SERVER_END_REQ;
368 return ret;
371 /**********************************************************************
372 * NtUserSetKeyboardState (win32u.@)
374 BOOL WINAPI NtUserSetKeyboardState( BYTE *state )
376 BOOL ret;
378 SERVER_START_REQ( set_key_state )
380 wine_server_add_data( req, state, 256 );
381 ret = !wine_server_call_err( req );
383 SERVER_END_REQ;
384 return ret;
387 /******************************************************************************
388 * NtUserVkKeyScanEx (win32u.@)
390 WORD WINAPI NtUserVkKeyScanEx( WCHAR chr, HKL layout )
392 WORD shift = 0x100, ctrl = 0x200;
393 SHORT ret;
395 TRACE_(keyboard)( "chr %s, layout %p\n", debugstr_wn(&chr, 1), layout );
397 if ((ret = user_driver->pVkKeyScanEx( chr, layout )) != -256) return ret;
399 /* FIXME: English keyboard layout specific */
401 if (chr == VK_CANCEL || chr == VK_BACK || chr == VK_TAB || chr == VK_RETURN ||
402 chr == VK_ESCAPE || chr == VK_SPACE) ret = chr;
403 else if (chr >= '0' && chr <= '9') ret = chr;
404 else if (chr == ')') ret = shift + '0';
405 else if (chr == '!') ret = shift + '1';
406 else if (chr == '@') ret = shift + '2';
407 else if (chr == '#') ret = shift + '3';
408 else if (chr == '$') ret = shift + '4';
409 else if (chr == '%') ret = shift + '5';
410 else if (chr == '^') ret = shift + '6';
411 else if (chr == '&') ret = shift + '7';
412 else if (chr == '*') ret = shift + '8';
413 else if (chr == '(') ret = shift + '9';
414 else if (chr >= 'a' && chr <= 'z') ret = chr - 'a' + 'A';
415 else if (chr >= 'A' && chr <= 'Z') ret = shift + chr;
416 else if (chr == ';') ret = VK_OEM_1;
417 else if (chr == '=') ret = VK_OEM_PLUS;
418 else if (chr == ',') ret = VK_OEM_COMMA;
419 else if (chr == '-') ret = VK_OEM_MINUS;
420 else if (chr == '.') ret = VK_OEM_PERIOD;
421 else if (chr == '/') ret = VK_OEM_2;
422 else if (chr == '`') ret = VK_OEM_3;
423 else if (chr == '[') ret = VK_OEM_4;
424 else if (chr == '\\') ret = VK_OEM_5;
425 else if (chr == ']') ret = VK_OEM_6;
426 else if (chr == '\'') ret = VK_OEM_7;
427 else if (chr == ':') ret = shift + VK_OEM_1;
428 else if (chr == '+') ret = shift + VK_OEM_PLUS;
429 else if (chr == '<') ret = shift + VK_OEM_COMMA;
430 else if (chr == '_') ret = shift + VK_OEM_MINUS;
431 else if (chr == '>') ret = shift + VK_OEM_PERIOD;
432 else if (chr == '?') ret = shift + VK_OEM_2;
433 else if (chr == '~') ret = shift + VK_OEM_3;
434 else if (chr == '{') ret = shift + VK_OEM_4;
435 else if (chr == '|') ret = shift + VK_OEM_5;
436 else if (chr == '}') ret = shift + VK_OEM_6;
437 else if (chr == '\"') ret = shift + VK_OEM_7;
438 else if (chr == 0x7f) ret = ctrl + VK_BACK;
439 else if (chr == '\n') ret = ctrl + VK_RETURN;
440 else if (chr == 0xf000) ret = ctrl + '2';
441 else if (chr == 0x0000) ret = ctrl + shift + '2';
442 else if (chr >= 0x0001 && chr <= 0x001a) ret = ctrl + 'A' + chr - 1;
443 else if (chr >= 0x001c && chr <= 0x001d) ret = ctrl + VK_OEM_3 + chr;
444 else if (chr == 0x001e) ret = ctrl + shift + '6';
445 else if (chr == 0x001f) ret = ctrl + shift + VK_OEM_MINUS;
446 else ret = -1;
448 TRACE_(keyboard)( "ret %04x\n", ret );
449 return ret;
452 /* English keyboard layout (0x0409) */
453 static const UINT kbd_en_vsc2vk[] =
455 0x00, 0x1b, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0xbd, 0xbb, 0x08, 0x09,
456 0x51, 0x57, 0x45, 0x52, 0x54, 0x59, 0x55, 0x49, 0x4f, 0x50, 0xdb, 0xdd, 0x0d, 0xa2, 0x41, 0x53,
457 0x44, 0x46, 0x47, 0x48, 0x4a, 0x4b, 0x4c, 0xba, 0xde, 0xc0, 0xa0, 0xdc, 0x5a, 0x58, 0x43, 0x56,
458 0x42, 0x4e, 0x4d, 0xbc, 0xbe, 0xbf, 0xa1, 0x6a, 0xa4, 0x20, 0x14, 0x70, 0x71, 0x72, 0x73, 0x74,
459 0x75, 0x76, 0x77, 0x78, 0x79, 0x90, 0x91, 0x24, 0x26, 0x21, 0x6d, 0x25, 0x0c, 0x27, 0x6b, 0x23,
460 0x28, 0x22, 0x2d, 0x2e, 0x2c, 0x00, 0xe2, 0x7a, 0x7b, 0x0c, 0xee, 0xf1, 0xea, 0xf9, 0xf5, 0xf3,
461 0x00, 0x00, 0xfb, 0x2f, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0xed,
462 0x00, 0xe9, 0x00, 0xc1, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, 0x00, 0xeb, 0x09, 0x00, 0xc2, 0x00,
463 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
464 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
465 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
466 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
467 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
468 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
469 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
470 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
471 /* 0xe000 */
472 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
473 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x0d, 0xa3, 0x00, 0x00,
474 0xad, 0xb7, 0xb3, 0x00, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xae, 0x00,
475 0xaf, 0x00, 0xac, 0x00, 0x00, 0x6f, 0x00, 0x2c, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
476 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x24, 0x26, 0x21, 0x00, 0x25, 0x00, 0x27, 0x00, 0x23,
477 0x28, 0x22, 0x2d, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5b, 0x5c, 0x5d, 0x00, 0x5f,
478 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xab, 0xa8, 0xa9, 0xa7, 0xa6, 0xb6, 0xb4, 0xb5, 0x00, 0x00,
479 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
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, 0x00, 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 /* 0xe100 */
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, 0x13, 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,
496 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
497 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
498 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
499 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
500 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
501 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
502 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
503 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
504 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
507 static const UINT kbd_en_vk2char[] =
509 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x08, 0x09, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00,
510 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00,
511 ' ', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
512 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
513 0x00, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
514 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 0x00, 0x00, 0x00, 0x00, 0x00,
515 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '*', '+', 0x00, '-', '.', '/',
516 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
517 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
518 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
519 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
520 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ';', '=', ',', '-', '.', '/',
521 '`', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
522 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, '[', '\\', ']', '\'', 0x00,
523 0x00, 0x00, '\\', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
524 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
527 static const char *kbd_en_vscname[] =
529 0, "Esc", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Backspace", "Tab",
530 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Enter", "Ctrl", 0, 0,
531 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Shift", 0, 0, 0, 0, 0,
532 0, 0, 0, 0, 0, 0, "Right Shift", "Num *", "Alt", "Space", "Caps Lock", "F1", "F2", "F3", "F4", "F5",
533 "F6", "F7", "F8", "F9", "F10", "Pause", "Scroll Lock", "Num 7", "Num 8", "Num 9", "Num -", "Num 4", "Num 5", "Num 6", "Num +", "Num 1",
534 "Num 2", "Num 3", "Num 0", "Num Del", "Sys Req", 0, 0, "F11", "F12", 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 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "F13", "F14", "F15", "F16",
537 "F17", "F18", "F19", "F20", "F21", "F22", "F23", "F24", 0, 0, 0, 0, 0, 0, 0, 0,
538 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
541 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
542 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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 /* extended */
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, "Num Enter", "Right Ctrl", 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, "Num /", 0, "Prnt Scrn", "Right Alt", 0, 0, 0, 0, 0, 0, 0,
550 0, 0, 0, 0, 0, "Num Lock", "Break", "Home", "Up", "Page Up", 0, "Left", 0, "Right", 0, "End",
551 "Down", "Page Down", "Insert", "Delete", "<00>", 0, "Help", 0, 0, 0, 0, "Left Windows", "Right Windows", "Application", 0, 0,
552 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
553 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
554 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
555 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
556 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
557 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
558 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
559 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
560 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
561 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
564 /******************************************************************************
565 * NtUserMapVirtualKeyEx (win32u.@)
567 UINT WINAPI NtUserMapVirtualKeyEx( UINT code, UINT type, HKL layout )
569 const UINT *vsc2vk, *vk2char;
570 UINT vsc2vk_size, vk2char_size;
571 UINT ret;
573 TRACE_(keyboard)( "code %u, type %u, layout %p.\n", code, type, layout );
575 if ((ret = user_driver->pMapVirtualKeyEx( code, type, layout )) != -1) return ret;
577 /* FIXME: English keyboard layout specific */
579 vsc2vk = kbd_en_vsc2vk;
580 vsc2vk_size = ARRAYSIZE(kbd_en_vsc2vk);
581 vk2char = kbd_en_vk2char;
582 vk2char_size = ARRAYSIZE(kbd_en_vk2char);
584 switch (type)
586 case MAPVK_VK_TO_VSC_EX:
587 case MAPVK_VK_TO_VSC:
588 switch (code)
590 case VK_SHIFT: code = VK_LSHIFT; break;
591 case VK_CONTROL: code = VK_LCONTROL; break;
592 case VK_MENU: code = VK_LMENU; break;
593 case VK_NUMPAD0: code = VK_INSERT; break;
594 case VK_NUMPAD1: code = VK_END; break;
595 case VK_NUMPAD2: code = VK_DOWN; break;
596 case VK_NUMPAD3: code = VK_NEXT; break;
597 case VK_NUMPAD4: code = VK_LEFT; break;
598 case VK_NUMPAD5: code = VK_CLEAR; break;
599 case VK_NUMPAD6: code = VK_RIGHT; break;
600 case VK_NUMPAD7: code = VK_HOME; break;
601 case VK_NUMPAD8: code = VK_UP; break;
602 case VK_NUMPAD9: code = VK_PRIOR; break;
603 case VK_DECIMAL: code = VK_DELETE; break;
606 for (ret = 0; ret < vsc2vk_size; ++ret) if (vsc2vk[ret] == code) break;
607 if (ret >= vsc2vk_size) ret = 0;
609 if (type == MAPVK_VK_TO_VSC)
611 if (ret >= 0x200) ret = 0;
612 else ret &= 0xff;
614 else if (ret >= 0x100) ret += 0xdf00;
615 break;
616 case MAPVK_VSC_TO_VK:
617 case MAPVK_VSC_TO_VK_EX:
618 if (code & 0xe000) code -= 0xdf00;
619 if (code >= vsc2vk_size) ret = 0;
620 else ret = vsc2vk[code];
622 if (type == MAPVK_VSC_TO_VK)
624 switch (ret)
626 case VK_LSHIFT: case VK_RSHIFT: ret = VK_SHIFT; break;
627 case VK_LCONTROL: case VK_RCONTROL: ret = VK_CONTROL; break;
628 case VK_LMENU: case VK_RMENU: ret = VK_MENU; break;
631 break;
632 case MAPVK_VK_TO_CHAR:
633 if (code >= vk2char_size) ret = 0;
634 else ret = vk2char[code];
635 break;
636 default:
637 FIXME_(keyboard)( "unknown type %d\n", type );
638 return 0;
641 TRACE_(keyboard)( "returning 0x%04x\n", ret );
642 return ret;
645 /****************************************************************************
646 * NtUserGetKeyNameText (win32u.@)
648 INT WINAPI NtUserGetKeyNameText( LONG lparam, WCHAR *buffer, INT size )
650 INT code = ((lparam >> 16) & 0x1ff), vkey, len;
651 UINT vsc2vk_size, vscname_size;
652 const char *const *vscname;
653 const UINT *vsc2vk;
655 TRACE_(keyboard)( "lparam %d, buffer %p, size %d.\n", lparam, buffer, size );
657 if (!buffer || !size) return 0;
658 if ((len = user_driver->pGetKeyNameText( lparam, buffer, size )) >= 0) return len;
660 /* FIXME: English keyboard layout specific */
662 vsc2vk = kbd_en_vsc2vk;
663 vsc2vk_size = ARRAYSIZE(kbd_en_vsc2vk);
664 vscname = kbd_en_vscname;
665 vscname_size = ARRAYSIZE(kbd_en_vscname);
667 if (lparam & 0x2000000)
669 switch ((vkey = vsc2vk[code]))
671 case VK_RSHIFT:
672 case VK_RCONTROL:
673 case VK_RMENU:
674 for (code = 0; code < vsc2vk_size; ++code)
675 if (vsc2vk[code] == (vkey - 1)) break;
676 break;
680 if (code < vscname_size)
682 if (vscname[code])
684 len = min( size - 1, strlen(vscname[code]) );
685 ascii_to_unicode( buffer, vscname[code], len );
687 else if (size > 1)
689 HKL hkl = NtUserGetKeyboardLayout( 0 );
690 vkey = NtUserMapVirtualKeyEx( code & 0xff, MAPVK_VSC_TO_VK, hkl );
691 buffer[0] = NtUserMapVirtualKeyEx( vkey, MAPVK_VK_TO_CHAR, hkl );
692 len = 1;
695 buffer[len] = 0;
697 TRACE_(keyboard)( "ret %d, str %s.\n", len, debugstr_w(buffer) );
698 return len;
701 /****************************************************************************
702 * NtUserToUnicodeEx (win32u.@)
704 INT WINAPI NtUserToUnicodeEx( UINT virt, UINT scan, const BYTE *state,
705 WCHAR *str, int size, UINT flags, HKL layout )
707 BOOL shift, ctrl, alt, numlock;
708 WCHAR buffer[2];
709 INT len;
711 TRACE_(keyboard)( "virt %u, scan %u, state %p, str %p, size %d, flags %x, layout %p.\n",
712 virt, scan, state, str, size, flags, layout );
714 if (!state) return 0;
715 if ((len = user_driver->pToUnicodeEx( virt, scan, state, str, size, flags, layout )) >= -1)
716 return len;
718 alt = state[VK_MENU] & 0x80;
719 shift = state[VK_SHIFT] & 0x80;
720 ctrl = state[VK_CONTROL] & 0x80;
721 numlock = state[VK_NUMLOCK] & 0x01;
723 /* FIXME: English keyboard layout specific */
725 if (scan & 0x8000) buffer[0] = 0; /* key up */
726 else if (virt == VK_ESCAPE) buffer[0] = VK_ESCAPE;
727 else if (!ctrl)
729 switch (virt)
731 case VK_BACK: buffer[0] = '\b'; break;
732 case VK_OEM_1: buffer[0] = shift ? ':' : ';'; break;
733 case VK_OEM_2: buffer[0] = shift ? '?' : '/'; break;
734 case VK_OEM_3: buffer[0] = shift ? '~' : '`'; break;
735 case VK_OEM_4: buffer[0] = shift ? '{' : '['; break;
736 case VK_OEM_5: buffer[0] = shift ? '|' : '\\'; break;
737 case VK_OEM_6: buffer[0] = shift ? '}' : ']'; break;
738 case VK_OEM_7: buffer[0] = shift ? '"' : '\''; break;
739 case VK_OEM_COMMA: buffer[0] = shift ? '<' : ','; break;
740 case VK_OEM_MINUS: buffer[0] = shift ? '_' : '-'; break;
741 case VK_OEM_PERIOD: buffer[0] = shift ? '>' : '.'; break;
742 case VK_OEM_PLUS: buffer[0] = shift ? '+' : '='; break;
743 case VK_RETURN: buffer[0] = '\r'; break;
744 case VK_SPACE: buffer[0] = ' '; break;
745 case VK_TAB: buffer[0] = '\t'; break;
746 case VK_MULTIPLY: buffer[0] = '*'; break;
747 case VK_ADD: buffer[0] = '+'; break;
748 case VK_SUBTRACT: buffer[0] = '-'; break;
749 case VK_DIVIDE: buffer[0] = '/'; break;
750 default:
751 if (virt >= '0' && virt <= '9')
752 buffer[0] = shift ? ")!@#$%^&*("[virt - '0'] : virt;
753 else if (virt >= 'A' && virt <= 'Z')
754 buffer[0] = shift || (state[VK_CAPITAL] & 0x01) ? virt : virt + 'a' - 'A';
755 else if (virt >= VK_NUMPAD0 && virt <= VK_NUMPAD9 && numlock && !shift)
756 buffer[0] = '0' + virt - VK_NUMPAD0;
757 else if (virt == VK_DECIMAL && numlock && !shift)
758 buffer[0] = '.';
759 else
760 buffer[0] = 0;
761 break;
764 else if (!alt) /* Control codes */
766 switch (virt)
768 case VK_OEM_4: buffer[0] = 0x1b; break;
769 case VK_OEM_5: buffer[0] = 0x1c; break;
770 case VK_OEM_6: buffer[0] = 0x1d; break;
771 case '6': buffer[0] = shift ? 0x1e : 0; break;
772 case VK_OEM_MINUS: buffer[0] = shift ? 0x1f : 0; break;
773 case VK_BACK: buffer[0] = 0x7f; break;
774 case VK_RETURN: buffer[0] = shift ? 0 : '\n'; break;
775 case '2': buffer[0] = shift ? 0xffff : 0xf000; break;
776 case VK_SPACE: buffer[0] = ' '; break;
777 default:
778 if (virt >= 'A' && virt <= 'Z') buffer[0] = virt - 'A' + 1;
779 else buffer[0] = 0;
780 break;
783 else buffer[0] = 0;
784 buffer[1] = 0;
785 len = lstrlenW( buffer );
786 if (buffer[0] == 0xffff) buffer[0] = 0;
787 lstrcpynW( str, buffer, size );
789 TRACE_(keyboard)( "ret %d, str %s.\n", len, debugstr_w(str) );
790 return len;
793 /**********************************************************************
794 * NtUserActivateKeyboardLayout (win32u.@)
796 HKL WINAPI NtUserActivateKeyboardLayout( HKL layout, UINT flags )
798 struct user_thread_info *info = get_user_thread_info();
799 HKL old_layout;
801 TRACE_(keyboard)( "layout %p, flags %x\n", layout, flags );
803 if (flags) FIXME_(keyboard)( "flags %x not supported\n", flags );
805 if (layout == (HKL)HKL_NEXT || layout == (HKL)HKL_PREV)
807 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
808 FIXME_(keyboard)( "HKL_NEXT and HKL_PREV not supported\n" );
809 return 0;
812 if (!user_driver->pActivateKeyboardLayout( layout, flags ))
813 return 0;
815 old_layout = info->kbd_layout;
816 info->kbd_layout = layout;
817 if (old_layout != layout) info->kbd_layout_id = 0;
819 if (!old_layout) return get_locale_kbd_layout();
820 return old_layout;
825 /***********************************************************************
826 * NtUserGetKeyboardLayoutList (win32u.@)
828 * Return number of values available if either input parm is
829 * 0, per MS documentation.
831 UINT WINAPI NtUserGetKeyboardLayoutList( INT size, HKL *layouts )
833 char buffer[4096];
834 KEY_NODE_INFORMATION *key_info = (KEY_NODE_INFORMATION *)buffer;
835 KEY_VALUE_PARTIAL_INFORMATION *value_info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
836 DWORD count, tmp, i = 0;
837 HKEY hkey, subkey;
838 HKL layout;
840 TRACE_(keyboard)( "size %d, layouts %p.\n", size, layouts );
842 if ((count = user_driver->pGetKeyboardLayoutList( size, layouts )) != ~0) return count;
844 layout = get_locale_kbd_layout();
845 count = 0;
847 count++;
848 if (size && layouts)
850 layouts[count - 1] = layout;
851 if (count == size) return count;
854 if ((hkey = reg_open_key( NULL, keyboard_layouts_keyW, sizeof(keyboard_layouts_keyW) )))
856 while (!NtEnumerateKey( hkey, i++, KeyNodeInformation, key_info,
857 sizeof(buffer) - sizeof(WCHAR), &tmp ))
859 if (!(subkey = reg_open_key( hkey, key_info->Name, key_info->NameLength ))) continue;
860 key_info->Name[key_info->NameLength / sizeof(WCHAR)] = 0;
861 tmp = wcstoul( key_info->Name, NULL, 16 );
862 if (query_reg_ascii_value( subkey, "Layout Id", value_info, sizeof(buffer) ) &&
863 value_info->Type == REG_SZ)
864 tmp = MAKELONG( LOWORD( tmp ),
865 0xf000 | (wcstoul( (const WCHAR *)value_info->Data, NULL, 16 ) & 0xfff) );
866 NtClose( subkey );
868 if (layout == UlongToHandle( tmp )) continue;
870 count++;
871 if (size && layouts)
873 layouts[count - 1] = UlongToHandle( tmp );
874 if (count == size) break;
877 NtClose( hkey );
880 return count;
883 /****************************************************************************
884 * NtUserGetKeyboardLayoutName (win32u.@)
886 BOOL WINAPI NtUserGetKeyboardLayoutName( WCHAR *name )
888 struct user_thread_info *info = get_user_thread_info();
889 char buffer[4096];
890 KEY_NODE_INFORMATION *key = (KEY_NODE_INFORMATION *)buffer;
891 KEY_VALUE_PARTIAL_INFORMATION *value = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
892 WCHAR klid[KL_NAMELENGTH];
893 DWORD tmp, i = 0;
894 HKEY hkey, subkey;
895 HKL layout;
897 TRACE_(keyboard)( "name %p\n", name );
899 if (!name)
901 SetLastError( ERROR_NOACCESS );
902 return FALSE;
905 if (info->kbd_layout_id)
907 sprintf( buffer, "%08X", info->kbd_layout_id );
908 asciiz_to_unicode( name, buffer );
909 return TRUE;
912 layout = NtUserGetKeyboardLayout( 0 );
913 tmp = HandleToUlong( layout );
914 if (HIWORD( tmp ) == LOWORD( tmp )) tmp = LOWORD( tmp );
915 sprintf( buffer, "%08X", tmp );
916 asciiz_to_unicode( name, buffer );
918 if ((hkey = reg_open_key( NULL, keyboard_layouts_keyW, sizeof(keyboard_layouts_keyW) )))
920 while (!NtEnumerateKey( hkey, i++, KeyNodeInformation, key,
921 sizeof(buffer) - sizeof(WCHAR), &tmp ))
923 if (!(subkey = reg_open_key( hkey, key->Name, key->NameLength ))) continue;
924 memcpy( klid, key->Name, key->NameLength );
925 klid[key->NameLength / sizeof(WCHAR)] = 0;
926 if (query_reg_ascii_value( subkey, "Layout Id", value, sizeof(buffer) ) &&
927 value->Type == REG_SZ)
928 tmp = 0xf000 | (wcstoul( (const WCHAR *)value->Data, NULL, 16 ) & 0xfff);
929 else
930 tmp = wcstoul( klid, NULL, 16 );
931 NtClose( subkey );
933 if (HIWORD( layout ) == tmp)
935 lstrcpynW( name, klid, KL_NAMELENGTH );
936 break;
939 NtClose( hkey );
942 info->kbd_layout_id = wcstoul( name, NULL, 16 );
944 TRACE_(keyboard)( "ret %s\n", debugstr_w( name ) );
945 return TRUE;
948 /***********************************************************************
949 * NtUserRegisterHotKey (win32u.@)
951 BOOL WINAPI NtUserRegisterHotKey( HWND hwnd, INT id, UINT modifiers, UINT vk )
953 BOOL ret;
954 int replaced = 0;
956 TRACE_(keyboard)( "(%p,%d,0x%08x,%X)\n", hwnd, id, modifiers, vk );
958 if ((!hwnd || is_current_thread_window( hwnd )) &&
959 !user_driver->pRegisterHotKey( hwnd, modifiers, vk ))
960 return FALSE;
962 SERVER_START_REQ( register_hotkey )
964 req->window = wine_server_user_handle( hwnd );
965 req->id = id;
966 req->flags = modifiers;
967 req->vkey = vk;
968 if ((ret = !wine_server_call_err( req )))
970 replaced = reply->replaced;
971 modifiers = reply->flags;
972 vk = reply->vkey;
975 SERVER_END_REQ;
977 if (ret && replaced)
978 user_driver->pUnregisterHotKey(hwnd, modifiers, vk);
980 return ret;
983 /***********************************************************************
984 * NtUserUnregisterHotKey (win32u.@)
986 BOOL WINAPI NtUserUnregisterHotKey( HWND hwnd, INT id )
988 BOOL ret;
989 UINT modifiers, vk;
991 TRACE_(keyboard)("(%p,%d)\n",hwnd,id);
993 SERVER_START_REQ( unregister_hotkey )
995 req->window = wine_server_user_handle( hwnd );
996 req->id = id;
997 if ((ret = !wine_server_call_err( req )))
999 modifiers = reply->flags;
1000 vk = reply->vkey;
1003 SERVER_END_REQ;
1005 if (ret)
1006 user_driver->pUnregisterHotKey(hwnd, modifiers, vk);
1008 return ret;
1011 /***********************************************************************
1012 * NtUserGetMouseMovePointsEx (win32u.@)
1014 int WINAPI NtUserGetMouseMovePointsEx( UINT size, MOUSEMOVEPOINT *ptin, MOUSEMOVEPOINT *ptout,
1015 int count, DWORD resolution )
1017 cursor_pos_t *pos, positions[64];
1018 int copied;
1019 unsigned int i;
1022 TRACE( "%d, %p, %p, %d, %d\n", size, ptin, ptout, count, resolution );
1024 if ((size != sizeof(MOUSEMOVEPOINT)) || (count < 0) || (count > ARRAY_SIZE( positions )))
1026 SetLastError( ERROR_INVALID_PARAMETER );
1027 return -1;
1030 if (!ptin || (!ptout && count))
1032 SetLastError( ERROR_NOACCESS );
1033 return -1;
1036 if (resolution != GMMP_USE_DISPLAY_POINTS)
1038 FIXME( "only GMMP_USE_DISPLAY_POINTS is supported for now\n" );
1039 SetLastError( ERROR_POINT_NOT_FOUND );
1040 return -1;
1043 SERVER_START_REQ( get_cursor_history )
1045 wine_server_set_reply( req, &positions, sizeof(positions) );
1046 if (wine_server_call_err( req )) return -1;
1048 SERVER_END_REQ;
1050 for (i = 0; i < ARRAY_SIZE( positions ); i++)
1052 pos = &positions[i];
1053 if (ptin->x == pos->x && ptin->y == pos->y && (!ptin->time || ptin->time == pos->time))
1054 break;
1057 if (i == ARRAY_SIZE( positions ))
1059 SetLastError( ERROR_POINT_NOT_FOUND );
1060 return -1;
1063 for (copied = 0; copied < count && i < ARRAY_SIZE( positions ); copied++, i++)
1065 pos = &positions[i];
1066 ptout[copied].x = pos->x;
1067 ptout[copied].y = pos->y;
1068 ptout[copied].time = pos->time;
1069 ptout[copied].dwExtraInfo = pos->info;
1072 return copied;
1075 /**********************************************************************
1076 * set_capture_window
1078 BOOL set_capture_window( HWND hwnd, UINT gui_flags, HWND *prev_ret )
1080 HWND previous = 0;
1081 UINT flags = 0;
1082 BOOL ret;
1084 if (gui_flags & GUI_INMENUMODE) flags |= CAPTURE_MENU;
1085 if (gui_flags & GUI_INMOVESIZE) flags |= CAPTURE_MOVESIZE;
1087 SERVER_START_REQ( set_capture_window )
1089 req->handle = wine_server_user_handle( hwnd );
1090 req->flags = flags;
1091 if ((ret = !wine_server_call_err( req )))
1093 previous = wine_server_ptr_handle( reply->previous );
1094 hwnd = wine_server_ptr_handle( reply->full_handle );
1097 SERVER_END_REQ;
1099 if (ret)
1101 user_driver->pSetCapture( hwnd, gui_flags );
1103 if (previous)
1104 send_message( previous, WM_CAPTURECHANGED, 0, (LPARAM)hwnd );
1106 if (prev_ret) *prev_ret = previous;
1108 return ret;
1111 /**********************************************************************
1112 * NtUserSetCapture (win32u.@)
1114 HWND WINAPI NtUserSetCapture( HWND hwnd )
1116 HWND previous = 0;
1118 set_capture_window( hwnd, 0, &previous );
1119 return previous;
1122 /**********************************************************************
1123 * release_capture
1125 BOOL WINAPI release_capture(void)
1127 BOOL ret = set_capture_window( 0, 0, NULL );
1129 /* Somebody may have missed some mouse movements */
1130 if (ret)
1132 INPUT input = { .type = INPUT_MOUSE };
1133 input.mi.dwFlags = MOUSEEVENTF_MOVE;
1134 NtUserSendInput( 1, &input, sizeof(input) );
1137 return ret;
1140 /*******************************************************************
1141 * NtUserGetForegroundWindow (win32u.@)
1143 HWND WINAPI NtUserGetForegroundWindow(void)
1145 HWND ret = 0;
1147 SERVER_START_REQ( get_thread_input )
1149 req->tid = 0;
1150 if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->foreground );
1152 SERVER_END_REQ;
1153 return ret;
1156 /* see GetActiveWindow */
1157 HWND get_active_window(void)
1159 GUITHREADINFO info;
1160 info.cbSize = sizeof(info);
1161 return NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info ) ? info.hwndActive : 0;
1164 /* see GetFocus */
1165 HWND get_focus(void)
1167 GUITHREADINFO info;
1168 info.cbSize = sizeof(info);
1169 return NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info ) ? info.hwndFocus : 0;
1172 /*****************************************************************
1173 * set_focus_window
1175 * Change the focus window, sending the WM_SETFOCUS and WM_KILLFOCUS messages
1177 static HWND set_focus_window( HWND hwnd )
1179 HWND previous = 0;
1180 BOOL ret;
1182 SERVER_START_REQ( set_focus_window )
1184 req->handle = wine_server_user_handle( hwnd );
1185 if ((ret = !wine_server_call_err( req )))
1186 previous = wine_server_ptr_handle( reply->previous );
1188 SERVER_END_REQ;
1189 if (!ret) return 0;
1190 if (previous == hwnd) return previous;
1192 if (previous)
1194 send_message( previous, WM_KILLFOCUS, (WPARAM)hwnd, 0 );
1196 if (user_callbacks) user_callbacks->notify_ime( previous, IME_INTERNAL_DEACTIVATE );
1198 if (hwnd != get_focus()) return previous; /* changed by the message */
1200 if (is_window(hwnd))
1202 user_driver->pSetFocus(hwnd);
1204 if (user_callbacks) user_callbacks->notify_ime( hwnd, IME_INTERNAL_ACTIVATE );
1206 if (previous)
1207 NtUserNotifyWinEvent( EVENT_OBJECT_FOCUS, hwnd, OBJID_CLIENT, 0 );
1209 send_message( hwnd, WM_SETFOCUS, (WPARAM)previous, 0 );
1211 return previous;
1214 /*******************************************************************
1215 * set_active_window
1217 static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus )
1219 HWND previous = get_active_window();
1220 BOOL ret;
1221 DWORD old_thread, new_thread;
1222 CBTACTIVATESTRUCT cbt;
1224 if (previous == hwnd)
1226 if (prev) *prev = hwnd;
1227 return TRUE;
1230 /* call CBT hook chain */
1231 cbt.fMouse = mouse;
1232 cbt.hWndActive = previous;
1233 if (call_hooks( WH_CBT, HCBT_ACTIVATE, (WPARAM)hwnd, (LPARAM)&cbt, TRUE )) return FALSE;
1235 if (is_window( previous ))
1237 send_message( previous, WM_NCACTIVATE, FALSE, (LPARAM)hwnd );
1238 send_message( previous, WM_ACTIVATE,
1239 MAKEWPARAM( WA_INACTIVE, is_iconic(previous) ), (LPARAM)hwnd );
1242 SERVER_START_REQ( set_active_window )
1244 req->handle = wine_server_user_handle( hwnd );
1245 if ((ret = !wine_server_call_err( req )))
1246 previous = wine_server_ptr_handle( reply->previous );
1248 SERVER_END_REQ;
1249 if (!ret) return FALSE;
1250 if (prev) *prev = previous;
1251 if (previous == hwnd) return TRUE;
1253 if (hwnd)
1255 /* send palette messages */
1256 if (send_message( hwnd, WM_QUERYNEWPALETTE, 0, 0 ) && user_callbacks)
1257 user_callbacks->pSendMessageTimeoutW( HWND_BROADCAST, WM_PALETTEISCHANGING, (WPARAM)hwnd, 0,
1258 SMTO_ABORTIFHUNG, 2000, NULL );
1259 if (!is_window(hwnd)) return FALSE;
1262 old_thread = previous ? get_window_thread( previous, NULL ) : 0;
1263 new_thread = hwnd ? get_window_thread( hwnd, NULL ) : 0;
1265 if (old_thread != new_thread)
1267 HWND *list, *phwnd;
1269 if ((list = list_window_children( NULL, get_desktop_window(), NULL, 0 )))
1271 if (old_thread)
1273 for (phwnd = list; *phwnd; phwnd++)
1275 if (get_window_thread( *phwnd, NULL ) == old_thread)
1276 send_message( *phwnd, WM_ACTIVATEAPP, 0, new_thread );
1279 if (new_thread)
1281 for (phwnd = list; *phwnd; phwnd++)
1283 if (get_window_thread( *phwnd, NULL ) == new_thread)
1284 send_message( *phwnd, WM_ACTIVATEAPP, 1, old_thread );
1287 free( list );
1291 if (is_window(hwnd))
1293 send_message( hwnd, WM_NCACTIVATE, hwnd == NtUserGetForegroundWindow(), (LPARAM)previous );
1294 send_message( hwnd, WM_ACTIVATE,
1295 MAKEWPARAM( mouse ? WA_CLICKACTIVE : WA_ACTIVE, is_iconic(hwnd) ),
1296 (LPARAM)previous );
1297 if (NtUserGetAncestor( hwnd, GA_PARENT ) == get_desktop_window())
1298 post_message( get_desktop_window(), WM_PARENTNOTIFY, WM_NCACTIVATE, (LPARAM)hwnd );
1301 /* now change focus if necessary */
1302 if (focus)
1304 GUITHREADINFO info;
1306 info.cbSize = sizeof(info);
1307 NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info );
1308 /* Do not change focus if the window is no more active */
1309 if (hwnd == info.hwndActive)
1311 if (!info.hwndFocus || !hwnd || NtUserGetAncestor( info.hwndFocus, GA_ROOT ) != hwnd)
1312 set_focus_window( hwnd );
1316 return TRUE;
1319 /**********************************************************************
1320 * NtUserSetActiveWindow (win32u.@)
1322 HWND WINAPI NtUserSetActiveWindow( HWND hwnd )
1324 HWND prev;
1326 TRACE( "%p\n", hwnd );
1328 if (hwnd)
1330 LONG style;
1332 hwnd = get_full_window_handle( hwnd );
1333 if (!is_window( hwnd ))
1335 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1336 return 0;
1339 style = get_window_long( hwnd, GWL_STYLE );
1340 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD)
1341 return get_active_window(); /* Windows doesn't seem to return an error here */
1344 if (!set_active_window( hwnd, &prev, FALSE, TRUE )) return 0;
1345 return prev;
1348 /*****************************************************************
1349 * NtUserSetFocus (win32u.@)
1351 HWND WINAPI NtUserSetFocus( HWND hwnd )
1353 HWND hwndTop = hwnd;
1354 HWND previous = get_focus();
1356 TRACE( "%p prev %p\n", hwnd, previous );
1358 if (hwnd)
1360 /* Check if we can set the focus to this window */
1361 hwnd = get_full_window_handle( hwnd );
1362 if (!is_window( hwnd ))
1364 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1365 return 0;
1367 if (hwnd == previous) return previous; /* nothing to do */
1368 for (;;)
1370 HWND parent;
1371 LONG style = get_window_long( hwndTop, GWL_STYLE );
1372 if (style & (WS_MINIMIZE | WS_DISABLED)) return 0;
1373 if (!(style & WS_CHILD)) break;
1374 parent = NtUserGetAncestor( hwndTop, GA_PARENT );
1375 if (!parent || parent == get_desktop_window())
1377 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return 0;
1378 break;
1380 if (parent == get_hwnd_message_parent()) return 0;
1381 hwndTop = parent;
1384 /* call hooks */
1385 if (call_hooks( WH_CBT, HCBT_SETFOCUS, (WPARAM)hwnd, (LPARAM)previous, TRUE )) return 0;
1387 /* activate hwndTop if needed. */
1388 if (hwndTop != get_active_window())
1390 if (!set_active_window( hwndTop, NULL, FALSE, FALSE )) return 0;
1391 if (!is_window( hwnd )) return 0; /* Abort if window destroyed */
1393 /* Do not change focus if the window is no longer active */
1394 if (hwndTop != get_active_window()) return 0;
1397 else /* NULL hwnd passed in */
1399 if (!previous) return 0; /* nothing to do */
1400 if (call_hooks( WH_CBT, HCBT_SETFOCUS, 0, (LPARAM)previous, TRUE )) return 0;
1403 /* change focus and send messages */
1404 return set_focus_window( hwnd );
1407 /*******************************************************************
1408 * set_foreground_window
1410 BOOL set_foreground_window( HWND hwnd, BOOL mouse )
1412 BOOL ret, send_msg_old = FALSE, send_msg_new = FALSE;
1413 HWND previous = 0;
1415 if (mouse) hwnd = get_full_window_handle( hwnd );
1417 SERVER_START_REQ( set_foreground_window )
1419 req->handle = wine_server_user_handle( hwnd );
1420 if ((ret = !wine_server_call_err( req )))
1422 previous = wine_server_ptr_handle( reply->previous );
1423 send_msg_old = reply->send_msg_old;
1424 send_msg_new = reply->send_msg_new;
1427 SERVER_END_REQ;
1429 if (ret && previous != hwnd)
1431 if (send_msg_old) /* old window belongs to other thread */
1432 NtUserMessageCall( previous, WM_WINE_SETACTIVEWINDOW, 0, 0,
1433 0, FNID_SENDNOTIFYMESSAGE, FALSE );
1434 else if (send_msg_new) /* old window belongs to us but new one to other thread */
1435 ret = set_active_window( 0, NULL, mouse, TRUE );
1437 if (send_msg_new) /* new window belongs to other thread */
1438 NtUserMessageCall( hwnd, WM_WINE_SETACTIVEWINDOW, (WPARAM)hwnd, 0,
1439 0, FNID_SENDNOTIFYMESSAGE, FALSE );
1440 else /* new window belongs to us */
1441 ret = set_active_window( hwnd, NULL, mouse, TRUE );
1443 return ret;