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
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
)
57 SERVER_START_REQ( attach_thread_input
)
62 ret
= !wine_server_call_err( req
);
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
)
84 INT prev_x
, prev_y
, new_x
, new_y
;
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
;
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
;
107 if (ret
&& (prev_x
!= new_x
|| prev_y
!= new_y
)) user_driver
->pSetCursorPos( new_x
, new_y
);
111 /***********************************************************************
114 BOOL
get_cursor_pos( POINT
*pt
)
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
;
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
);
143 /***********************************************************************
144 * NtUserGetCursorInfo (win32u.@)
146 BOOL WINAPI
NtUserGetCursorInfo( CURSORINFO
*info
)
150 if (!info
) return FALSE
;
152 SERVER_START_REQ( get_thread_input
)
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;
162 get_cursor_pos( &info
->ptScreenPos
);
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
;
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 */
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
;
199 SERVER_START_REQ( get_key_state
)
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;
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
;
230 /***********************************************************************
231 * NtUserGetQueueStatus (win32u.@)
233 DWORD WINAPI
NtUserGetQueueStatus( UINT flags
)
237 if (flags
& ~(QS_ALLINPUT
| QS_ALLPOSTMESSAGE
| QS_SMRESULT
))
239 SetLastError( ERROR_INVALID_FLAGS
);
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
);
255 /***********************************************************************
258 DWORD
get_input_state(void)
262 check_for_events( QS_INPUT
);
264 SERVER_START_REQ( get_queue_status
)
267 wine_server_call( req
);
268 ret
= reply
->wake_bits
& (QS_KEY
| QS_MOUSEBUTTON
);
274 /***********************************************************************
275 * get_locale_kbd_layout
277 static HKL
get_locale_kbd_layout(void)
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 */
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();
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
)
339 SERVER_START_REQ( get_key_state
)
342 if (!wine_server_call( req
)) retval
= (signed char)(reply
->state
& 0x81);
345 TRACE("key (0x%x) -> %x\n", vkey
, retval
);
349 /**********************************************************************
350 * NtUserGetKeyboardState (win32u.@)
352 BOOL WINAPI
NtUserGetKeyboardState( BYTE
*state
)
357 TRACE("(%p)\n", state
);
359 memset( state
, 0, 256 );
360 SERVER_START_REQ( get_key_state
)
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;
371 /**********************************************************************
372 * NtUserSetKeyboardState (win32u.@)
374 BOOL WINAPI
NtUserSetKeyboardState( BYTE
*state
)
378 SERVER_START_REQ( set_key_state
)
380 wine_server_add_data( req
, state
, 256 );
381 ret
= !wine_server_call_err( req
);
387 /******************************************************************************
388 * NtUserVkKeyScanEx (win32u.@)
390 WORD WINAPI
NtUserVkKeyScanEx( WCHAR chr
, HKL layout
)
392 WORD shift
= 0x100, ctrl
= 0x200;
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
;
448 TRACE_(keyboard
)( "ret %04x\n", 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,
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,
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,
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
;
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
);
586 case MAPVK_VK_TO_VSC_EX
:
587 case MAPVK_VK_TO_VSC
:
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;
614 else if (ret
>= 0x100) ret
+= 0xdf00;
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
)
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;
632 case MAPVK_VK_TO_CHAR
:
633 if (code
>= vk2char_size
) ret
= 0;
634 else ret
= vk2char
[code
];
637 FIXME_(keyboard
)( "unknown type %d\n", type
);
641 TRACE_(keyboard
)( "returning 0x%04x\n", 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
;
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
]))
674 for (code
= 0; code
< vsc2vk_size
; ++code
)
675 if (vsc2vk
[code
] == (vkey
- 1)) break;
680 if (code
< vscname_size
)
684 len
= min( size
- 1, strlen(vscname
[code
]) );
685 ascii_to_unicode( buffer
, vscname
[code
], len
);
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
);
697 TRACE_(keyboard
)( "ret %d, str %s.\n", len
, debugstr_w(buffer
) );
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
;
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)
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
;
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;
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
)
764 else if (!alt
) /* Control codes */
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;
778 if (virt
>= 'A' && virt
<= 'Z') buffer
[0] = virt
- 'A' + 1;
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
) );
793 /**********************************************************************
794 * NtUserActivateKeyboardLayout (win32u.@)
796 HKL WINAPI
NtUserActivateKeyboardLayout( HKL layout
, UINT flags
)
798 struct user_thread_info
*info
= get_user_thread_info();
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" );
812 if (!user_driver
->pActivateKeyboardLayout( layout
, flags
))
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();
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
)
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;
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();
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) );
868 if (layout
== UlongToHandle( tmp
)) continue;
873 layouts
[count
- 1] = UlongToHandle( tmp
);
874 if (count
== size
) break;
883 /****************************************************************************
884 * NtUserGetKeyboardLayoutName (win32u.@)
886 BOOL WINAPI
NtUserGetKeyboardLayoutName( WCHAR
*name
)
888 struct user_thread_info
*info
= get_user_thread_info();
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
];
897 TRACE_(keyboard
)( "name %p\n", name
);
901 SetLastError( ERROR_NOACCESS
);
905 if (info
->kbd_layout_id
)
907 sprintf( buffer
, "%08X", info
->kbd_layout_id
);
908 asciiz_to_unicode( name
, buffer
);
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);
930 tmp
= wcstoul( klid
, NULL
, 16 );
933 if (HIWORD( layout
) == tmp
)
935 lstrcpynW( name
, klid
, KL_NAMELENGTH
);
942 info
->kbd_layout_id
= wcstoul( name
, NULL
, 16 );
944 TRACE_(keyboard
)( "ret %s\n", debugstr_w( name
) );
948 /***********************************************************************
949 * NtUserRegisterHotKey (win32u.@)
951 BOOL WINAPI
NtUserRegisterHotKey( HWND hwnd
, INT id
, UINT modifiers
, UINT vk
)
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
))
962 SERVER_START_REQ( register_hotkey
)
964 req
->window
= wine_server_user_handle( hwnd
);
966 req
->flags
= modifiers
;
968 if ((ret
= !wine_server_call_err( req
)))
970 replaced
= reply
->replaced
;
971 modifiers
= reply
->flags
;
978 user_driver
->pUnregisterHotKey(hwnd
, modifiers
, vk
);
983 /***********************************************************************
984 * NtUserUnregisterHotKey (win32u.@)
986 BOOL WINAPI
NtUserUnregisterHotKey( HWND hwnd
, INT id
)
991 TRACE_(keyboard
)("(%p,%d)\n",hwnd
,id
);
993 SERVER_START_REQ( unregister_hotkey
)
995 req
->window
= wine_server_user_handle( hwnd
);
997 if ((ret
= !wine_server_call_err( req
)))
999 modifiers
= reply
->flags
;
1006 user_driver
->pUnregisterHotKey(hwnd
, modifiers
, vk
);
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];
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
);
1030 if (!ptin
|| (!ptout
&& count
))
1032 SetLastError( ERROR_NOACCESS
);
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
);
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;
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
))
1057 if (i
== ARRAY_SIZE( positions
))
1059 SetLastError( ERROR_POINT_NOT_FOUND
);
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
;
1075 /**********************************************************************
1076 * set_capture_window
1078 BOOL
set_capture_window( HWND hwnd
, UINT gui_flags
, HWND
*prev_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
);
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
);
1101 user_driver
->pSetCapture( hwnd
, gui_flags
);
1104 send_message( previous
, WM_CAPTURECHANGED
, 0, (LPARAM
)hwnd
);
1106 if (prev_ret
) *prev_ret
= previous
;
1111 /**********************************************************************
1112 * NtUserSetCapture (win32u.@)
1114 HWND WINAPI
NtUserSetCapture( HWND hwnd
)
1118 set_capture_window( hwnd
, 0, &previous
);
1122 /**********************************************************************
1125 BOOL WINAPI
release_capture(void)
1127 BOOL ret
= set_capture_window( 0, 0, NULL
);
1129 /* Somebody may have missed some mouse movements */
1132 INPUT input
= { .type
= INPUT_MOUSE
};
1133 input
.mi
.dwFlags
= MOUSEEVENTF_MOVE
;
1134 NtUserSendInput( 1, &input
, sizeof(input
) );
1140 /*******************************************************************
1141 * NtUserGetForegroundWindow (win32u.@)
1143 HWND WINAPI
NtUserGetForegroundWindow(void)
1147 SERVER_START_REQ( get_thread_input
)
1150 if (!wine_server_call_err( req
)) ret
= wine_server_ptr_handle( reply
->foreground
);
1156 /* see GetActiveWindow */
1157 HWND
get_active_window(void)
1160 info
.cbSize
= sizeof(info
);
1161 return NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info
) ? info
.hwndActive
: 0;
1165 HWND
get_focus(void)
1168 info
.cbSize
= sizeof(info
);
1169 return NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info
) ? info
.hwndFocus
: 0;
1172 /*****************************************************************
1175 * Change the focus window, sending the WM_SETFOCUS and WM_KILLFOCUS messages
1177 static HWND
set_focus_window( HWND hwnd
)
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
);
1190 if (previous
== hwnd
) return 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
);
1207 NtUserNotifyWinEvent( EVENT_OBJECT_FOCUS
, hwnd
, OBJID_CLIENT
, 0 );
1209 send_message( hwnd
, WM_SETFOCUS
, (WPARAM
)previous
, 0 );
1214 /*******************************************************************
1217 static BOOL
set_active_window( HWND hwnd
, HWND
*prev
, BOOL mouse
, BOOL focus
)
1219 HWND previous
= get_active_window();
1221 DWORD old_thread
, new_thread
;
1222 CBTACTIVATESTRUCT cbt
;
1224 if (previous
== hwnd
)
1226 if (prev
) *prev
= hwnd
;
1230 /* call CBT hook chain */
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
);
1249 if (!ret
) return FALSE
;
1250 if (prev
) *prev
= previous
;
1251 if (previous
== hwnd
) return TRUE
;
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
)
1269 if ((list
= list_window_children( NULL
, get_desktop_window(), NULL
, 0 )))
1273 for (phwnd
= list
; *phwnd
; phwnd
++)
1275 if (get_window_thread( *phwnd
, NULL
) == old_thread
)
1276 send_message( *phwnd
, WM_ACTIVATEAPP
, 0, 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
);
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
) ),
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 */
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
);
1319 /**********************************************************************
1320 * NtUserSetActiveWindow (win32u.@)
1322 HWND WINAPI
NtUserSetActiveWindow( HWND hwnd
)
1326 TRACE( "%p\n", hwnd
);
1332 hwnd
= get_full_window_handle( hwnd
);
1333 if (!is_window( hwnd
))
1335 SetLastError( ERROR_INVALID_WINDOW_HANDLE
);
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;
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
);
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
);
1367 if (hwnd
== previous
) return previous
; /* nothing to do */
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;
1380 if (parent
== get_hwnd_message_parent()) return 0;
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
;
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
;
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
);