2 * USER Input processing
4 * Copyright 1993 Bob Amstadt
5 * Copyright 1993 David Metcalfe
6 * Copyright 1996 Albrecht Kleine
7 * Copyright 1996 Frans van Dorsselaer
8 * Copyright 1997 David Faure
9 * Copyright 1998 Morten Welinder
10 * Copyright 1998 Ulrich Weigand
11 * Copyright 2001 Eric Pouech
12 * Copyright 2002 Alexandre Julliard
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
34 #define WIN32_NO_STATUS
35 #include "win32u_private.h"
36 #include "ntuser_private.h"
37 #include "wine/server.h"
38 #include "wine/debug.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(win
);
41 WINE_DECLARE_DEBUG_CHANNEL(keyboard
);
43 static const WCHAR keyboard_layouts_keyW
[] =
45 '\\','R','e','g','i','s','t','r','y',
46 '\\','M','a','c','h','i','n','e',
47 '\\','S','y','s','t','e','m',
48 '\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t',
49 '\\','C','o','n','t','r','o','l',
50 '\\','K','e','y','b','o','a','r','d',' ','L','a','y','o','u','t','s'
54 LONG global_key_state_counter
= 0;
56 /**********************************************************************
57 * NtUserAttachThreadInput (win32u.@)
59 BOOL WINAPI
NtUserAttachThreadInput( DWORD from
, DWORD to
, BOOL attach
)
63 SERVER_START_REQ( attach_thread_input
)
68 ret
= !wine_server_call_err( req
);
74 /***********************************************************************
75 * __wine_send_input (win32u.@)
77 * Internal SendInput function to allow the graphics driver to inject real events.
79 BOOL CDECL
__wine_send_input( HWND hwnd
, const INPUT
*input
, const RAWINPUT
*rawinput
)
81 return set_ntstatus( send_hardware_message( hwnd
, input
, rawinput
, 0 ));
84 /***********************************************************************
87 * Helper for NtUserSendInput.
89 static void update_mouse_coords( INPUT
*input
)
91 if (!(input
->mi
.dwFlags
& MOUSEEVENTF_MOVE
)) return;
93 if (input
->mi
.dwFlags
& MOUSEEVENTF_ABSOLUTE
)
97 if (input
->mi
.dwFlags
& MOUSEEVENTF_VIRTUALDESK
)
98 rc
= get_virtual_screen_rect( 0 );
100 rc
= get_primary_monitor_rect( 0 );
102 input
->mi
.dx
= rc
.left
+ ((input
->mi
.dx
* (rc
.right
- rc
.left
)) >> 16);
103 input
->mi
.dy
= rc
.top
+ ((input
->mi
.dy
* (rc
.bottom
- rc
.top
)) >> 16);
109 /* dx and dy can be negative numbers for relative movements */
110 NtUserSystemParametersInfo( SPI_GETMOUSE
, 0, accel
, 0 );
112 if (!accel
[2]) return;
114 if (abs( input
->mi
.dx
) > accel
[0])
117 if (abs( input
->mi
.dx
) > accel
[1] && accel
[2] == 2) input
->mi
.dx
*= 2;
119 if (abs(input
->mi
.dy
) > accel
[0])
122 if (abs( input
->mi
.dy
) > accel
[1] && accel
[2] == 2) input
->mi
.dy
*= 2;
127 /***********************************************************************
128 * NtUserSendInput (win32u.@)
130 UINT WINAPI
NtUserSendInput( UINT count
, INPUT
*inputs
, int size
)
133 NTSTATUS status
= STATUS_SUCCESS
;
135 if (size
!= sizeof(INPUT
))
137 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
143 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
149 RtlSetLastWin32Error( ERROR_NOACCESS
);
153 for (i
= 0; i
< count
; i
++)
155 INPUT input
= inputs
[i
];
159 /* we need to update the coordinates to what the server expects */
160 update_mouse_coords( &input
);
163 status
= send_hardware_message( 0, &input
, NULL
, SEND_HWMSG_INJECTED
);
166 RtlSetLastWin32Error( ERROR_CALL_NOT_IMPLEMENTED
);
172 RtlSetLastWin32Error( RtlNtStatusToDosError(status
) );
180 /***********************************************************************
181 * NtUserSetCursorPos (win32u.@)
183 BOOL WINAPI
NtUserSetCursorPos( INT x
, INT y
)
187 INT prev_x
, prev_y
, new_x
, new_y
;
190 if ((dpi
= get_thread_dpi()))
192 HMONITOR monitor
= monitor_from_point( pt
, MONITOR_DEFAULTTOPRIMARY
, get_thread_dpi() );
193 pt
= map_dpi_point( pt
, dpi
, get_monitor_dpi( monitor
));
196 SERVER_START_REQ( set_cursor
)
198 req
->flags
= SET_CURSOR_POS
;
201 if ((ret
= !wine_server_call( req
)))
203 prev_x
= reply
->prev_x
;
204 prev_y
= reply
->prev_y
;
205 new_x
= reply
->new_x
;
206 new_y
= reply
->new_y
;
210 if (ret
&& (prev_x
!= new_x
|| prev_y
!= new_y
)) user_driver
->pSetCursorPos( new_x
, new_y
);
214 /***********************************************************************
217 BOOL
get_cursor_pos( POINT
*pt
)
223 if (!pt
) return FALSE
;
225 SERVER_START_REQ( set_cursor
)
227 if ((ret
= !wine_server_call( req
)))
229 pt
->x
= reply
->new_x
;
230 pt
->y
= reply
->new_y
;
231 last_change
= reply
->last_change
;
236 /* query new position from graphics driver if we haven't updated recently */
237 if (ret
&& NtGetTickCount() - last_change
> 100) ret
= user_driver
->pGetCursorPos( pt
);
238 if (ret
&& (dpi
= get_thread_dpi()))
240 HMONITOR monitor
= monitor_from_point( *pt
, MONITOR_DEFAULTTOPRIMARY
, 0 );
241 *pt
= map_dpi_point( *pt
, get_monitor_dpi( monitor
), dpi
);
246 /***********************************************************************
247 * NtUserGetCursorInfo (win32u.@)
249 BOOL WINAPI
NtUserGetCursorInfo( CURSORINFO
*info
)
253 if (!info
) return FALSE
;
255 SERVER_START_REQ( get_thread_input
)
258 if ((ret
= !wine_server_call( req
)))
260 info
->hCursor
= wine_server_ptr_handle( reply
->cursor
);
261 info
->flags
= reply
->show_count
>= 0 ? CURSOR_SHOWING
: 0;
265 get_cursor_pos( &info
->ptScreenPos
);
269 static void check_for_events( UINT flags
)
271 LARGE_INTEGER zero
= { .QuadPart
= 0 };
272 if (user_driver
->pMsgWaitForMultipleObjectsEx( 0, NULL
, &zero
, flags
, 0 ) == WAIT_TIMEOUT
)
273 flush_window_surfaces( TRUE
);
276 /**********************************************************************
277 * GetAsyncKeyState (win32u.@)
279 SHORT WINAPI
NtUserGetAsyncKeyState( INT key
)
281 struct user_key_state_info
*key_state_info
= get_user_thread_info()->key_state
;
282 INT counter
= global_key_state_counter
;
286 if (key
< 0 || key
>= 256) return 0;
288 check_for_events( QS_INPUT
);
290 if (key_state_info
&& !(key_state_info
->state
[key
] & 0xc0) &&
291 key_state_info
->counter
== counter
&& NtGetTickCount() - key_state_info
->time
< 50)
293 /* use cached value */
296 else if (!key_state_info
)
298 key_state_info
= calloc( 1, sizeof(*key_state_info
) );
299 get_user_thread_info()->key_state
= key_state_info
;
303 SERVER_START_REQ( get_key_state
)
309 prev_key_state
= key_state_info
->state
[key
];
310 wine_server_set_reply( req
, key_state_info
->state
, sizeof(key_state_info
->state
) );
312 if (!wine_server_call( req
))
314 if (reply
->state
& 0x40) ret
|= 0x0001;
315 if (reply
->state
& 0x80) ret
|= 0x8000;
318 /* force refreshing the key state cache - some multithreaded programs
319 * (like Adobe Photoshop CS5) expect that changes to the async key state
320 * are also immediately available in other threads. */
321 if (prev_key_state
!= key_state_info
->state
[key
])
322 counter
= InterlockedIncrement( &global_key_state_counter
);
324 key_state_info
->time
= NtGetTickCount();
325 key_state_info
->counter
= counter
;
334 /***********************************************************************
335 * NtUserGetQueueStatus (win32u.@)
337 DWORD WINAPI
NtUserGetQueueStatus( UINT flags
)
341 if (flags
& ~(QS_ALLINPUT
| QS_ALLPOSTMESSAGE
| QS_SMRESULT
))
343 RtlSetLastWin32Error( ERROR_INVALID_FLAGS
);
347 check_for_events( flags
);
349 SERVER_START_REQ( get_queue_status
)
351 req
->clear_bits
= flags
;
352 wine_server_call( req
);
353 ret
= MAKELONG( reply
->changed_bits
& flags
, reply
->wake_bits
& flags
);
359 /***********************************************************************
362 DWORD
get_input_state(void)
366 check_for_events( QS_INPUT
);
368 SERVER_START_REQ( get_queue_status
)
371 wine_server_call( req
);
372 ret
= reply
->wake_bits
& (QS_KEY
| QS_MOUSEBUTTON
);
378 /***********************************************************************
379 * get_locale_kbd_layout
381 static HKL
get_locale_kbd_layout(void)
388 * layout = main_key_tab[kbd_layout].lcid;
390 * Winword uses return value of GetKeyboardLayout as a codepage
391 * to translate ANSI keyboard messages to unicode. But we have
392 * a problem with it: for instance Polish keyboard layout is
393 * identical to the US one, and therefore instead of the Polish
394 * locale id we return the US one.
397 NtQueryDefaultLocale( TRUE
, &layout
);
400 * Microsoft Office expects this value to be something specific
401 * for Japanese and Korean Windows with an IME the value is 0xe001
402 * We should probably check to see if an IME exists and if so then
403 * set this word properly.
405 langid
= PRIMARYLANGID( LANGIDFROMLCID( layout
) );
406 if (langid
== LANG_CHINESE
|| langid
== LANG_JAPANESE
|| langid
== LANG_KOREAN
)
407 layout
= MAKELONG( layout
, 0xe001 ); /* IME */
409 layout
= MAKELONG( layout
, layout
);
411 return ULongToHandle( layout
);
414 /***********************************************************************
415 * NtUserGetKeyboardLayout (win32u.@)
417 * Device handle for keyboard layout defaulted to
418 * the language id. This is the way Windows default works.
420 HKL WINAPI
NtUserGetKeyboardLayout( DWORD thread_id
)
422 struct user_thread_info
*thread
= get_user_thread_info();
423 HKL layout
= thread
->kbd_layout
;
425 if (thread_id
&& thread_id
!= GetCurrentThreadId())
426 FIXME( "couldn't return keyboard layout for thread %04x\n", thread_id
);
428 if (!layout
) return get_locale_kbd_layout();
432 /**********************************************************************
433 * NtUserGetKeyState (win32u.@)
435 * An application calls the GetKeyState function in response to a
436 * keyboard-input message. This function retrieves the state of the key
437 * at the time the input message was generated.
439 SHORT WINAPI
NtUserGetKeyState( INT vkey
)
443 SERVER_START_REQ( get_key_state
)
446 if (!wine_server_call( req
)) retval
= (signed char)(reply
->state
& 0x81);
449 TRACE("key (0x%x) -> %x\n", vkey
, retval
);
453 /**********************************************************************
454 * NtUserGetKeyboardState (win32u.@)
456 BOOL WINAPI
NtUserGetKeyboardState( BYTE
*state
)
461 TRACE("(%p)\n", state
);
463 memset( state
, 0, 256 );
464 SERVER_START_REQ( get_key_state
)
467 wine_server_set_reply( req
, state
, 256 );
468 ret
= !wine_server_call_err( req
);
469 for (i
= 0; i
< 256; i
++) state
[i
] &= 0x81;
475 /**********************************************************************
476 * NtUserSetKeyboardState (win32u.@)
478 BOOL WINAPI
NtUserSetKeyboardState( BYTE
*state
)
482 SERVER_START_REQ( set_key_state
)
484 wine_server_add_data( req
, state
, 256 );
485 ret
= !wine_server_call_err( req
);
491 /******************************************************************************
492 * NtUserVkKeyScanEx (win32u.@)
494 WORD WINAPI
NtUserVkKeyScanEx( WCHAR chr
, HKL layout
)
496 WORD shift
= 0x100, ctrl
= 0x200;
499 TRACE_(keyboard
)( "chr %s, layout %p\n", debugstr_wn(&chr
, 1), layout
);
501 if ((ret
= user_driver
->pVkKeyScanEx( chr
, layout
)) != -256) return ret
;
503 /* FIXME: English keyboard layout specific */
505 if (chr
== VK_CANCEL
|| chr
== VK_BACK
|| chr
== VK_TAB
|| chr
== VK_RETURN
||
506 chr
== VK_ESCAPE
|| chr
== VK_SPACE
) ret
= chr
;
507 else if (chr
>= '0' && chr
<= '9') ret
= chr
;
508 else if (chr
== ')') ret
= shift
+ '0';
509 else if (chr
== '!') ret
= shift
+ '1';
510 else if (chr
== '@') ret
= shift
+ '2';
511 else if (chr
== '#') ret
= shift
+ '3';
512 else if (chr
== '$') ret
= shift
+ '4';
513 else if (chr
== '%') ret
= shift
+ '5';
514 else if (chr
== '^') ret
= shift
+ '6';
515 else if (chr
== '&') ret
= shift
+ '7';
516 else if (chr
== '*') ret
= shift
+ '8';
517 else if (chr
== '(') ret
= shift
+ '9';
518 else if (chr
>= 'a' && chr
<= 'z') ret
= chr
- 'a' + 'A';
519 else if (chr
>= 'A' && chr
<= 'Z') ret
= shift
+ chr
;
520 else if (chr
== ';') ret
= VK_OEM_1
;
521 else if (chr
== '=') ret
= VK_OEM_PLUS
;
522 else if (chr
== ',') ret
= VK_OEM_COMMA
;
523 else if (chr
== '-') ret
= VK_OEM_MINUS
;
524 else if (chr
== '.') ret
= VK_OEM_PERIOD
;
525 else if (chr
== '/') ret
= VK_OEM_2
;
526 else if (chr
== '`') ret
= VK_OEM_3
;
527 else if (chr
== '[') ret
= VK_OEM_4
;
528 else if (chr
== '\\') ret
= VK_OEM_5
;
529 else if (chr
== ']') ret
= VK_OEM_6
;
530 else if (chr
== '\'') ret
= VK_OEM_7
;
531 else if (chr
== ':') ret
= shift
+ VK_OEM_1
;
532 else if (chr
== '+') ret
= shift
+ VK_OEM_PLUS
;
533 else if (chr
== '<') ret
= shift
+ VK_OEM_COMMA
;
534 else if (chr
== '_') ret
= shift
+ VK_OEM_MINUS
;
535 else if (chr
== '>') ret
= shift
+ VK_OEM_PERIOD
;
536 else if (chr
== '?') ret
= shift
+ VK_OEM_2
;
537 else if (chr
== '~') ret
= shift
+ VK_OEM_3
;
538 else if (chr
== '{') ret
= shift
+ VK_OEM_4
;
539 else if (chr
== '|') ret
= shift
+ VK_OEM_5
;
540 else if (chr
== '}') ret
= shift
+ VK_OEM_6
;
541 else if (chr
== '\"') ret
= shift
+ VK_OEM_7
;
542 else if (chr
== 0x7f) ret
= ctrl
+ VK_BACK
;
543 else if (chr
== '\n') ret
= ctrl
+ VK_RETURN
;
544 else if (chr
== 0xf000) ret
= ctrl
+ '2';
545 else if (chr
== 0x0000) ret
= ctrl
+ shift
+ '2';
546 else if (chr
>= 0x0001 && chr
<= 0x001a) ret
= ctrl
+ 'A' + chr
- 1;
547 else if (chr
>= 0x001c && chr
<= 0x001d) ret
= ctrl
+ VK_OEM_3
+ chr
;
548 else if (chr
== 0x001e) ret
= ctrl
+ shift
+ '6';
549 else if (chr
== 0x001f) ret
= ctrl
+ shift
+ VK_OEM_MINUS
;
552 TRACE_(keyboard
)( "ret %04x\n", ret
);
556 /* English keyboard layout (0x0409) */
557 static const UINT kbd_en_vsc2vk
[] =
559 0x00, 0x1b, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0xbd, 0xbb, 0x08, 0x09,
560 0x51, 0x57, 0x45, 0x52, 0x54, 0x59, 0x55, 0x49, 0x4f, 0x50, 0xdb, 0xdd, 0x0d, 0xa2, 0x41, 0x53,
561 0x44, 0x46, 0x47, 0x48, 0x4a, 0x4b, 0x4c, 0xba, 0xde, 0xc0, 0xa0, 0xdc, 0x5a, 0x58, 0x43, 0x56,
562 0x42, 0x4e, 0x4d, 0xbc, 0xbe, 0xbf, 0xa1, 0x6a, 0xa4, 0x20, 0x14, 0x70, 0x71, 0x72, 0x73, 0x74,
563 0x75, 0x76, 0x77, 0x78, 0x79, 0x90, 0x91, 0x24, 0x26, 0x21, 0x6d, 0x25, 0x0c, 0x27, 0x6b, 0x23,
564 0x28, 0x22, 0x2d, 0x2e, 0x2c, 0x00, 0xe2, 0x7a, 0x7b, 0x0c, 0xee, 0xf1, 0xea, 0xf9, 0xf5, 0xf3,
565 0x00, 0x00, 0xfb, 0x2f, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0xed,
566 0x00, 0xe9, 0x00, 0xc1, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, 0x00, 0xeb, 0x09, 0x00, 0xc2, 0x00,
567 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
568 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
569 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
570 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
571 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
572 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
573 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
574 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
576 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
577 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x0d, 0xa3, 0x00, 0x00,
578 0xad, 0xb7, 0xb3, 0x00, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xae, 0x00,
579 0xaf, 0x00, 0xac, 0x00, 0x00, 0x6f, 0x00, 0x2c, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
580 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x24, 0x26, 0x21, 0x00, 0x25, 0x00, 0x27, 0x00, 0x23,
581 0x28, 0x22, 0x2d, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5b, 0x5c, 0x5d, 0x00, 0x5f,
582 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xab, 0xa8, 0xa9, 0xa7, 0xa6, 0xb6, 0xb4, 0xb5, 0x00, 0x00,
583 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
584 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
585 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
586 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
587 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
588 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
589 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
590 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
591 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
593 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
594 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00,
595 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
596 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
597 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
598 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
599 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
600 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
601 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
602 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
603 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
604 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
605 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
606 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
607 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
608 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
611 static const UINT kbd_en_vk2char
[] =
613 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x08, 0x09, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00,
614 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00,
615 ' ', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
616 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
617 0x00, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
618 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 0x00, 0x00, 0x00, 0x00, 0x00,
619 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '*', '+', 0x00, '-', '.', '/',
620 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
621 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
622 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
623 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
624 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ';', '=', ',', '-', '.', '/',
625 '`', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
626 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, '[', '\\', ']', '\'', 0x00,
627 0x00, 0x00, '\\', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
628 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
631 static const char *kbd_en_vscname
[] =
633 0, "Esc", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Backspace", "Tab",
634 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Enter", "Ctrl", 0, 0,
635 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Shift", 0, 0, 0, 0, 0,
636 0, 0, 0, 0, 0, 0, "Right Shift", "Num *", "Alt", "Space", "Caps Lock", "F1", "F2", "F3", "F4", "F5",
637 "F6", "F7", "F8", "F9", "F10", "Pause", "Scroll Lock", "Num 7", "Num 8", "Num 9", "Num -", "Num 4", "Num 5", "Num 6", "Num +", "Num 1",
638 "Num 2", "Num 3", "Num 0", "Num Del", "Sys Req", 0, 0, "F11", "F12", 0, 0, 0, 0, 0, 0, 0,
639 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
640 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "F13", "F14", "F15", "F16",
641 "F17", "F18", "F19", "F20", "F21", "F22", "F23", "F24", 0, 0, 0, 0, 0, 0, 0, 0,
642 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
643 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
644 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
645 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
646 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
647 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
648 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
650 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
651 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Num Enter", "Right Ctrl", 0, 0,
652 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
653 0, 0, 0, 0, 0, "Num /", 0, "Prnt Scrn", "Right Alt", 0, 0, 0, 0, 0, 0, 0,
654 0, 0, 0, 0, 0, "Num Lock", "Break", "Home", "Up", "Page Up", 0, "Left", 0, "Right", 0, "End",
655 "Down", "Page Down", "Insert", "Delete", "<00>", 0, "Help", 0, 0, 0, 0, "Left Windows", "Right Windows", "Application", 0, 0,
656 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
657 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
658 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
659 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
660 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
661 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
662 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
663 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
664 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
665 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
668 /******************************************************************************
669 * NtUserMapVirtualKeyEx (win32u.@)
671 UINT WINAPI
NtUserMapVirtualKeyEx( UINT code
, UINT type
, HKL layout
)
673 const UINT
*vsc2vk
, *vk2char
;
674 UINT vsc2vk_size
, vk2char_size
;
677 TRACE_(keyboard
)( "code %u, type %u, layout %p.\n", code
, type
, layout
);
679 if ((ret
= user_driver
->pMapVirtualKeyEx( code
, type
, layout
)) != -1) return ret
;
681 /* FIXME: English keyboard layout specific */
683 vsc2vk
= kbd_en_vsc2vk
;
684 vsc2vk_size
= ARRAYSIZE(kbd_en_vsc2vk
);
685 vk2char
= kbd_en_vk2char
;
686 vk2char_size
= ARRAYSIZE(kbd_en_vk2char
);
690 case MAPVK_VK_TO_VSC_EX
:
691 case MAPVK_VK_TO_VSC
:
694 case VK_SHIFT
: code
= VK_LSHIFT
; break;
695 case VK_CONTROL
: code
= VK_LCONTROL
; break;
696 case VK_MENU
: code
= VK_LMENU
; break;
697 case VK_NUMPAD0
: code
= VK_INSERT
; break;
698 case VK_NUMPAD1
: code
= VK_END
; break;
699 case VK_NUMPAD2
: code
= VK_DOWN
; break;
700 case VK_NUMPAD3
: code
= VK_NEXT
; break;
701 case VK_NUMPAD4
: code
= VK_LEFT
; break;
702 case VK_NUMPAD5
: code
= VK_CLEAR
; break;
703 case VK_NUMPAD6
: code
= VK_RIGHT
; break;
704 case VK_NUMPAD7
: code
= VK_HOME
; break;
705 case VK_NUMPAD8
: code
= VK_UP
; break;
706 case VK_NUMPAD9
: code
= VK_PRIOR
; break;
707 case VK_DECIMAL
: code
= VK_DELETE
; break;
710 for (ret
= 0; ret
< vsc2vk_size
; ++ret
) if (vsc2vk
[ret
] == code
) break;
711 if (ret
>= vsc2vk_size
) ret
= 0;
713 if (type
== MAPVK_VK_TO_VSC
)
715 if (ret
>= 0x200) ret
= 0;
718 else if (ret
>= 0x100) ret
+= 0xdf00;
720 case MAPVK_VSC_TO_VK
:
721 case MAPVK_VSC_TO_VK_EX
:
722 if (code
& 0xe000) code
-= 0xdf00;
723 if (code
>= vsc2vk_size
) ret
= 0;
724 else ret
= vsc2vk
[code
];
726 if (type
== MAPVK_VSC_TO_VK
)
730 case VK_LSHIFT
: case VK_RSHIFT
: ret
= VK_SHIFT
; break;
731 case VK_LCONTROL
: case VK_RCONTROL
: ret
= VK_CONTROL
; break;
732 case VK_LMENU
: case VK_RMENU
: ret
= VK_MENU
; break;
736 case MAPVK_VK_TO_CHAR
:
737 if (code
>= vk2char_size
) ret
= 0;
738 else ret
= vk2char
[code
];
741 FIXME_(keyboard
)( "unknown type %d\n", type
);
745 TRACE_(keyboard
)( "returning 0x%04x\n", ret
);
749 /****************************************************************************
750 * NtUserGetKeyNameText (win32u.@)
752 INT WINAPI
NtUserGetKeyNameText( LONG lparam
, WCHAR
*buffer
, INT size
)
754 INT code
= ((lparam
>> 16) & 0x1ff), vkey
, len
;
755 UINT vsc2vk_size
, vscname_size
;
756 const char *const *vscname
;
759 TRACE_(keyboard
)( "lparam %d, buffer %p, size %d.\n", lparam
, buffer
, size
);
761 if (!buffer
|| !size
) return 0;
762 if ((len
= user_driver
->pGetKeyNameText( lparam
, buffer
, size
)) >= 0) return len
;
764 /* FIXME: English keyboard layout specific */
766 vsc2vk
= kbd_en_vsc2vk
;
767 vsc2vk_size
= ARRAYSIZE(kbd_en_vsc2vk
);
768 vscname
= kbd_en_vscname
;
769 vscname_size
= ARRAYSIZE(kbd_en_vscname
);
771 if (lparam
& 0x2000000)
773 switch ((vkey
= vsc2vk
[code
]))
778 for (code
= 0; code
< vsc2vk_size
; ++code
)
779 if (vsc2vk
[code
] == (vkey
- 1)) break;
784 if (code
< vscname_size
)
788 len
= min( size
- 1, strlen(vscname
[code
]) );
789 ascii_to_unicode( buffer
, vscname
[code
], len
);
793 HKL hkl
= NtUserGetKeyboardLayout( 0 );
794 vkey
= NtUserMapVirtualKeyEx( code
& 0xff, MAPVK_VSC_TO_VK
, hkl
);
795 buffer
[0] = NtUserMapVirtualKeyEx( vkey
, MAPVK_VK_TO_CHAR
, hkl
);
801 TRACE_(keyboard
)( "ret %d, str %s.\n", len
, debugstr_w(buffer
) );
805 /****************************************************************************
806 * NtUserToUnicodeEx (win32u.@)
808 INT WINAPI
NtUserToUnicodeEx( UINT virt
, UINT scan
, const BYTE
*state
,
809 WCHAR
*str
, int size
, UINT flags
, HKL layout
)
811 BOOL shift
, ctrl
, alt
, numlock
;
815 TRACE_(keyboard
)( "virt %u, scan %u, state %p, str %p, size %d, flags %x, layout %p.\n",
816 virt
, scan
, state
, str
, size
, flags
, layout
);
818 if (!state
) return 0;
819 if ((len
= user_driver
->pToUnicodeEx( virt
, scan
, state
, str
, size
, flags
, layout
)) >= -1)
822 alt
= state
[VK_MENU
] & 0x80;
823 shift
= state
[VK_SHIFT
] & 0x80;
824 ctrl
= state
[VK_CONTROL
] & 0x80;
825 numlock
= state
[VK_NUMLOCK
] & 0x01;
827 /* FIXME: English keyboard layout specific */
829 if (scan
& 0x8000) buffer
[0] = 0; /* key up */
830 else if (virt
== VK_ESCAPE
) buffer
[0] = VK_ESCAPE
;
835 case VK_BACK
: buffer
[0] = '\b'; break;
836 case VK_OEM_1
: buffer
[0] = shift
? ':' : ';'; break;
837 case VK_OEM_2
: buffer
[0] = shift
? '?' : '/'; break;
838 case VK_OEM_3
: buffer
[0] = shift
? '~' : '`'; break;
839 case VK_OEM_4
: buffer
[0] = shift
? '{' : '['; break;
840 case VK_OEM_5
: buffer
[0] = shift
? '|' : '\\'; break;
841 case VK_OEM_6
: buffer
[0] = shift
? '}' : ']'; break;
842 case VK_OEM_7
: buffer
[0] = shift
? '"' : '\''; break;
843 case VK_OEM_COMMA
: buffer
[0] = shift
? '<' : ','; break;
844 case VK_OEM_MINUS
: buffer
[0] = shift
? '_' : '-'; break;
845 case VK_OEM_PERIOD
: buffer
[0] = shift
? '>' : '.'; break;
846 case VK_OEM_PLUS
: buffer
[0] = shift
? '+' : '='; break;
847 case VK_RETURN
: buffer
[0] = '\r'; break;
848 case VK_SPACE
: buffer
[0] = ' '; break;
849 case VK_TAB
: buffer
[0] = '\t'; break;
850 case VK_MULTIPLY
: buffer
[0] = '*'; break;
851 case VK_ADD
: buffer
[0] = '+'; break;
852 case VK_SUBTRACT
: buffer
[0] = '-'; break;
853 case VK_DIVIDE
: buffer
[0] = '/'; break;
855 if (virt
>= '0' && virt
<= '9')
856 buffer
[0] = shift
? ")!@#$%^&*("[virt
- '0'] : virt
;
857 else if (virt
>= 'A' && virt
<= 'Z')
858 buffer
[0] = shift
|| (state
[VK_CAPITAL
] & 0x01) ? virt
: virt
+ 'a' - 'A';
859 else if (virt
>= VK_NUMPAD0
&& virt
<= VK_NUMPAD9
&& numlock
&& !shift
)
860 buffer
[0] = '0' + virt
- VK_NUMPAD0
;
861 else if (virt
== VK_DECIMAL
&& numlock
&& !shift
)
868 else if (!alt
) /* Control codes */
872 case VK_OEM_4
: buffer
[0] = 0x1b; break;
873 case VK_OEM_5
: buffer
[0] = 0x1c; break;
874 case VK_OEM_6
: buffer
[0] = 0x1d; break;
875 case '6': buffer
[0] = shift
? 0x1e : 0; break;
876 case VK_OEM_MINUS
: buffer
[0] = shift
? 0x1f : 0; break;
877 case VK_BACK
: buffer
[0] = 0x7f; break;
878 case VK_RETURN
: buffer
[0] = shift
? 0 : '\n'; break;
879 case '2': buffer
[0] = shift
? 0xffff : 0xf000; break;
880 case VK_SPACE
: buffer
[0] = ' '; break;
882 if (virt
>= 'A' && virt
<= 'Z') buffer
[0] = virt
- 'A' + 1;
889 len
= lstrlenW( buffer
);
890 if (buffer
[0] == 0xffff) buffer
[0] = 0;
891 lstrcpynW( str
, buffer
, size
);
893 TRACE_(keyboard
)( "ret %d, str %s.\n", len
, debugstr_w(str
) );
897 /**********************************************************************
898 * NtUserActivateKeyboardLayout (win32u.@)
900 HKL WINAPI
NtUserActivateKeyboardLayout( HKL layout
, UINT flags
)
902 struct user_thread_info
*info
= get_user_thread_info();
905 TRACE_(keyboard
)( "layout %p, flags %x\n", layout
, flags
);
907 if (flags
) FIXME_(keyboard
)( "flags %x not supported\n", flags
);
909 if (layout
== (HKL
)HKL_NEXT
|| layout
== (HKL
)HKL_PREV
)
911 RtlSetLastWin32Error( ERROR_CALL_NOT_IMPLEMENTED
);
912 FIXME_(keyboard
)( "HKL_NEXT and HKL_PREV not supported\n" );
916 if (!user_driver
->pActivateKeyboardLayout( layout
, flags
))
919 old_layout
= info
->kbd_layout
;
920 info
->kbd_layout
= layout
;
921 if (old_layout
!= layout
) info
->kbd_layout_id
= 0;
923 if (!old_layout
) return get_locale_kbd_layout();
929 /***********************************************************************
930 * NtUserGetKeyboardLayoutList (win32u.@)
932 * Return number of values available if either input parm is
933 * 0, per MS documentation.
935 UINT WINAPI
NtUserGetKeyboardLayoutList( INT size
, HKL
*layouts
)
938 KEY_NODE_INFORMATION
*key_info
= (KEY_NODE_INFORMATION
*)buffer
;
939 KEY_VALUE_PARTIAL_INFORMATION
*value_info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
940 DWORD count
, tmp
, i
= 0;
944 TRACE_(keyboard
)( "size %d, layouts %p.\n", size
, layouts
);
946 if ((count
= user_driver
->pGetKeyboardLayoutList( size
, layouts
)) != ~0) return count
;
948 layout
= get_locale_kbd_layout();
954 layouts
[count
- 1] = layout
;
955 if (count
== size
) return count
;
958 if ((hkey
= reg_open_key( NULL
, keyboard_layouts_keyW
, sizeof(keyboard_layouts_keyW
) )))
960 while (!NtEnumerateKey( hkey
, i
++, KeyNodeInformation
, key_info
,
961 sizeof(buffer
) - sizeof(WCHAR
), &tmp
))
963 if (!(subkey
= reg_open_key( hkey
, key_info
->Name
, key_info
->NameLength
))) continue;
964 key_info
->Name
[key_info
->NameLength
/ sizeof(WCHAR
)] = 0;
965 tmp
= wcstoul( key_info
->Name
, NULL
, 16 );
966 if (query_reg_ascii_value( subkey
, "Layout Id", value_info
, sizeof(buffer
) ) &&
967 value_info
->Type
== REG_SZ
)
968 tmp
= MAKELONG( LOWORD( tmp
),
969 0xf000 | (wcstoul( (const WCHAR
*)value_info
->Data
, NULL
, 16 ) & 0xfff) );
972 if (layout
== UlongToHandle( tmp
)) continue;
977 layouts
[count
- 1] = UlongToHandle( tmp
);
978 if (count
== size
) break;
987 /****************************************************************************
988 * NtUserGetKeyboardLayoutName (win32u.@)
990 BOOL WINAPI
NtUserGetKeyboardLayoutName( WCHAR
*name
)
992 struct user_thread_info
*info
= get_user_thread_info();
994 KEY_NODE_INFORMATION
*key
= (KEY_NODE_INFORMATION
*)buffer
;
995 KEY_VALUE_PARTIAL_INFORMATION
*value
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
996 WCHAR klid
[KL_NAMELENGTH
];
1001 TRACE_(keyboard
)( "name %p\n", name
);
1005 RtlSetLastWin32Error( ERROR_NOACCESS
);
1009 if (info
->kbd_layout_id
)
1011 sprintf( buffer
, "%08X", info
->kbd_layout_id
);
1012 asciiz_to_unicode( name
, buffer
);
1016 layout
= NtUserGetKeyboardLayout( 0 );
1017 tmp
= HandleToUlong( layout
);
1018 if (HIWORD( tmp
) == LOWORD( tmp
)) tmp
= LOWORD( tmp
);
1019 sprintf( buffer
, "%08X", tmp
);
1020 asciiz_to_unicode( name
, buffer
);
1022 if ((hkey
= reg_open_key( NULL
, keyboard_layouts_keyW
, sizeof(keyboard_layouts_keyW
) )))
1024 while (!NtEnumerateKey( hkey
, i
++, KeyNodeInformation
, key
,
1025 sizeof(buffer
) - sizeof(WCHAR
), &tmp
))
1027 if (!(subkey
= reg_open_key( hkey
, key
->Name
, key
->NameLength
))) continue;
1028 memcpy( klid
, key
->Name
, key
->NameLength
);
1029 klid
[key
->NameLength
/ sizeof(WCHAR
)] = 0;
1030 if (query_reg_ascii_value( subkey
, "Layout Id", value
, sizeof(buffer
) ) &&
1031 value
->Type
== REG_SZ
)
1032 tmp
= 0xf000 | (wcstoul( (const WCHAR
*)value
->Data
, NULL
, 16 ) & 0xfff);
1034 tmp
= wcstoul( klid
, NULL
, 16 );
1037 if (HIWORD( layout
) == tmp
)
1039 lstrcpynW( name
, klid
, KL_NAMELENGTH
);
1046 info
->kbd_layout_id
= wcstoul( name
, NULL
, 16 );
1048 TRACE_(keyboard
)( "ret %s\n", debugstr_w( name
) );
1052 /***********************************************************************
1053 * NtUserRegisterHotKey (win32u.@)
1055 BOOL WINAPI
NtUserRegisterHotKey( HWND hwnd
, INT id
, UINT modifiers
, UINT vk
)
1060 TRACE_(keyboard
)( "(%p,%d,0x%08x,%X)\n", hwnd
, id
, modifiers
, vk
);
1062 if ((!hwnd
|| is_current_thread_window( hwnd
)) &&
1063 !user_driver
->pRegisterHotKey( hwnd
, modifiers
, vk
))
1066 SERVER_START_REQ( register_hotkey
)
1068 req
->window
= wine_server_user_handle( hwnd
);
1070 req
->flags
= modifiers
;
1072 if ((ret
= !wine_server_call_err( req
)))
1074 replaced
= reply
->replaced
;
1075 modifiers
= reply
->flags
;
1081 if (ret
&& replaced
)
1082 user_driver
->pUnregisterHotKey(hwnd
, modifiers
, vk
);
1087 /***********************************************************************
1088 * NtUserUnregisterHotKey (win32u.@)
1090 BOOL WINAPI
NtUserUnregisterHotKey( HWND hwnd
, INT id
)
1095 TRACE_(keyboard
)("(%p,%d)\n",hwnd
,id
);
1097 SERVER_START_REQ( unregister_hotkey
)
1099 req
->window
= wine_server_user_handle( hwnd
);
1101 if ((ret
= !wine_server_call_err( req
)))
1103 modifiers
= reply
->flags
;
1110 user_driver
->pUnregisterHotKey(hwnd
, modifiers
, vk
);
1115 /***********************************************************************
1116 * NtUserGetMouseMovePointsEx (win32u.@)
1118 int WINAPI
NtUserGetMouseMovePointsEx( UINT size
, MOUSEMOVEPOINT
*ptin
, MOUSEMOVEPOINT
*ptout
,
1119 int count
, DWORD resolution
)
1121 cursor_pos_t
*pos
, positions
[64];
1126 TRACE( "%d, %p, %p, %d, %d\n", size
, ptin
, ptout
, count
, resolution
);
1128 if ((size
!= sizeof(MOUSEMOVEPOINT
)) || (count
< 0) || (count
> ARRAY_SIZE( positions
)))
1130 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
1134 if (!ptin
|| (!ptout
&& count
))
1136 RtlSetLastWin32Error( ERROR_NOACCESS
);
1140 if (resolution
!= GMMP_USE_DISPLAY_POINTS
)
1142 FIXME( "only GMMP_USE_DISPLAY_POINTS is supported for now\n" );
1143 RtlSetLastWin32Error( ERROR_POINT_NOT_FOUND
);
1147 SERVER_START_REQ( get_cursor_history
)
1149 wine_server_set_reply( req
, &positions
, sizeof(positions
) );
1150 if (wine_server_call_err( req
)) return -1;
1154 for (i
= 0; i
< ARRAY_SIZE( positions
); i
++)
1156 pos
= &positions
[i
];
1157 if (ptin
->x
== pos
->x
&& ptin
->y
== pos
->y
&& (!ptin
->time
|| ptin
->time
== pos
->time
))
1161 if (i
== ARRAY_SIZE( positions
))
1163 RtlSetLastWin32Error( ERROR_POINT_NOT_FOUND
);
1167 for (copied
= 0; copied
< count
&& i
< ARRAY_SIZE( positions
); copied
++, i
++)
1169 pos
= &positions
[i
];
1170 ptout
[copied
].x
= pos
->x
;
1171 ptout
[copied
].y
= pos
->y
;
1172 ptout
[copied
].time
= pos
->time
;
1173 ptout
[copied
].dwExtraInfo
= pos
->info
;
1179 static WORD
get_key_state(void)
1183 if (get_system_metrics( SM_SWAPBUTTON
))
1185 if (NtUserGetAsyncKeyState(VK_RBUTTON
) & 0x80) ret
|= MK_LBUTTON
;
1186 if (NtUserGetAsyncKeyState(VK_LBUTTON
) & 0x80) ret
|= MK_RBUTTON
;
1190 if (NtUserGetAsyncKeyState(VK_LBUTTON
) & 0x80) ret
|= MK_LBUTTON
;
1191 if (NtUserGetAsyncKeyState(VK_RBUTTON
) & 0x80) ret
|= MK_RBUTTON
;
1193 if (NtUserGetAsyncKeyState(VK_MBUTTON
) & 0x80) ret
|= MK_MBUTTON
;
1194 if (NtUserGetAsyncKeyState(VK_SHIFT
) & 0x80) ret
|= MK_SHIFT
;
1195 if (NtUserGetAsyncKeyState(VK_CONTROL
) & 0x80) ret
|= MK_CONTROL
;
1196 if (NtUserGetAsyncKeyState(VK_XBUTTON1
) & 0x80) ret
|= MK_XBUTTON1
;
1197 if (NtUserGetAsyncKeyState(VK_XBUTTON2
) & 0x80) ret
|= MK_XBUTTON2
;
1201 struct tracking_list
1203 TRACKMOUSEEVENT info
;
1204 POINT pos
; /* center of hover rectangle */
1207 /* FIXME: move tracking stuff into per-thread data */
1208 static struct tracking_list tracking_info
;
1210 static void check_mouse_leave( HWND hwnd
, int hittest
)
1212 if (tracking_info
.info
.hwndTrack
!= hwnd
)
1214 if (tracking_info
.info
.dwFlags
& TME_NONCLIENT
)
1215 NtUserPostMessage( tracking_info
.info
.hwndTrack
, WM_NCMOUSELEAVE
, 0, 0 );
1217 NtUserPostMessage( tracking_info
.info
.hwndTrack
, WM_MOUSELEAVE
, 0, 0 );
1219 tracking_info
.info
.dwFlags
&= ~TME_LEAVE
;
1223 if (hittest
== HTCLIENT
)
1225 if (tracking_info
.info
.dwFlags
& TME_NONCLIENT
)
1227 NtUserPostMessage( tracking_info
.info
.hwndTrack
, WM_NCMOUSELEAVE
, 0, 0 );
1228 tracking_info
.info
.dwFlags
&= ~TME_LEAVE
;
1233 if (!(tracking_info
.info
.dwFlags
& TME_NONCLIENT
))
1235 NtUserPostMessage( tracking_info
.info
.hwndTrack
, WM_MOUSELEAVE
, 0, 0 );
1236 tracking_info
.info
.dwFlags
&= ~TME_LEAVE
;
1242 void update_mouse_tracking_info( HWND hwnd
)
1244 int hover_width
= 0, hover_height
= 0, hittest
;
1247 TRACE( "hwnd %p\n", hwnd
);
1249 get_cursor_pos( &pos
);
1250 hwnd
= window_from_point( hwnd
, pos
, &hittest
);
1252 TRACE( "point %s hwnd %p hittest %d\n", wine_dbgstr_point(&pos
), hwnd
, hittest
);
1254 NtUserSystemParametersInfo( SPI_GETMOUSEHOVERWIDTH
, 0, &hover_width
, 0 );
1255 NtUserSystemParametersInfo( SPI_GETMOUSEHOVERHEIGHT
, 0, &hover_height
, 0 );
1257 TRACE( "tracked pos %s, current pos %s, hover width %d, hover height %d\n",
1258 wine_dbgstr_point(&tracking_info
.pos
), wine_dbgstr_point(&pos
),
1259 hover_width
, hover_height
);
1261 if (tracking_info
.info
.dwFlags
& TME_LEAVE
)
1262 check_mouse_leave( hwnd
, hittest
);
1264 if (tracking_info
.info
.hwndTrack
!= hwnd
)
1265 tracking_info
.info
.dwFlags
&= ~TME_HOVER
;
1267 if (tracking_info
.info
.dwFlags
& TME_HOVER
)
1269 /* has the cursor moved outside the rectangle centered around pos? */
1270 if ((abs( pos
.x
- tracking_info
.pos
.x
) > (hover_width
/ 2)) ||
1271 (abs( pos
.y
- tracking_info
.pos
.y
) > (hover_height
/ 2)))
1273 tracking_info
.pos
= pos
;
1277 if (hittest
== HTCLIENT
)
1279 screen_to_client(hwnd
, &pos
);
1280 TRACE( "client cursor pos %s\n", wine_dbgstr_point(&pos
) );
1282 NtUserPostMessage( tracking_info
.info
.hwndTrack
, WM_MOUSEHOVER
,
1283 get_key_state(), MAKELPARAM( pos
.x
, pos
.y
) );
1287 if (tracking_info
.info
.dwFlags
& TME_NONCLIENT
)
1288 NtUserPostMessage( tracking_info
.info
.hwndTrack
, WM_NCMOUSEHOVER
,
1289 hittest
, MAKELPARAM( pos
.x
, pos
.y
) );
1292 /* stop tracking mouse hover */
1293 tracking_info
.info
.dwFlags
&= ~TME_HOVER
;
1297 /* stop the timer if the tracking list is empty */
1298 if (!(tracking_info
.info
.dwFlags
& (TME_HOVER
| TME_LEAVE
)))
1300 kill_system_timer( tracking_info
.info
.hwndTrack
, SYSTEM_TIMER_TRACK_MOUSE
);
1301 tracking_info
.info
.hwndTrack
= 0;
1302 tracking_info
.info
.dwFlags
= 0;
1303 tracking_info
.info
.dwHoverTime
= 0;
1307 /***********************************************************************
1308 * NtUserTrackMouseEvent (win32u.@)
1310 BOOL WINAPI
NtUserTrackMouseEvent( TRACKMOUSEEVENT
*info
)
1317 TRACE( "size %u, flags %#x, hwnd %p, time %u\n",
1318 info
->cbSize
, info
->dwFlags
, info
->hwndTrack
, info
->dwHoverTime
);
1320 if (info
->cbSize
!= sizeof(TRACKMOUSEEVENT
))
1322 WARN( "wrong size %u\n", info
->cbSize
);
1323 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
1327 if (info
->dwFlags
& TME_QUERY
)
1329 *info
= tracking_info
.info
;
1330 info
->cbSize
= sizeof(TRACKMOUSEEVENT
);
1334 if (!is_window( info
->hwndTrack
))
1336 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
1340 hover_time
= (info
->dwFlags
& TME_HOVER
) ? info
->dwHoverTime
: HOVER_DEFAULT
;
1342 if (hover_time
== HOVER_DEFAULT
|| hover_time
== 0)
1343 NtUserSystemParametersInfo( SPI_GETMOUSEHOVERTIME
, 0, &hover_time
, 0 );
1345 get_cursor_pos( &pos
);
1346 hwnd
= window_from_point( info
->hwndTrack
, pos
, &hittest
);
1347 TRACE( "point %s hwnd %p hittest %d\n", wine_dbgstr_point(&pos
), hwnd
, hittest
);
1349 if (info
->dwFlags
& ~(TME_CANCEL
| TME_HOVER
| TME_LEAVE
| TME_NONCLIENT
))
1350 FIXME( "ignoring flags %#x\n", info
->dwFlags
& ~(TME_CANCEL
| TME_HOVER
| TME_LEAVE
| TME_NONCLIENT
) );
1352 if (info
->dwFlags
& TME_CANCEL
)
1354 if (tracking_info
.info
.hwndTrack
== info
->hwndTrack
)
1356 tracking_info
.info
.dwFlags
&= ~(info
->dwFlags
& ~TME_CANCEL
);
1358 /* if we aren't tracking on hover or leave remove this entry */
1359 if (!(tracking_info
.info
.dwFlags
& (TME_HOVER
| TME_LEAVE
)))
1361 kill_system_timer( tracking_info
.info
.hwndTrack
, SYSTEM_TIMER_TRACK_MOUSE
);
1362 tracking_info
.info
.hwndTrack
= 0;
1363 tracking_info
.info
.dwFlags
= 0;
1364 tracking_info
.info
.dwHoverTime
= 0;
1370 /* In our implementation, it's possible that another window will receive
1371 * WM_MOUSEMOVE and call TrackMouseEvent before TrackMouseEventProc is
1372 * called. In such a situation, post the WM_MOUSELEAVE now. */
1373 if ((tracking_info
.info
.dwFlags
& TME_LEAVE
) && tracking_info
.info
.hwndTrack
!= NULL
)
1374 check_mouse_leave(hwnd
, hittest
);
1376 kill_system_timer( tracking_info
.info
.hwndTrack
, SYSTEM_TIMER_TRACK_MOUSE
);
1377 tracking_info
.info
.hwndTrack
= 0;
1378 tracking_info
.info
.dwFlags
= 0;
1379 tracking_info
.info
.dwHoverTime
= 0;
1381 if (info
->hwndTrack
== hwnd
)
1383 /* Adding new mouse event to the tracking list */
1384 tracking_info
.info
= *info
;
1385 tracking_info
.info
.dwHoverTime
= hover_time
;
1387 /* Initialize HoverInfo variables even if not hover tracking */
1388 tracking_info
.pos
= pos
;
1390 NtUserSetSystemTimer( tracking_info
.info
.hwndTrack
, SYSTEM_TIMER_TRACK_MOUSE
, hover_time
);
1397 /*******************************************************************
1398 * NtUserDragDetect (win32u.@)
1400 BOOL WINAPI
NtUserDragDetect( HWND hwnd
, int x
, int y
)
1406 TRACE( "%p (%d,%d)\n", hwnd
, x
, y
);
1408 if (!(NtUserGetKeyState( VK_LBUTTON
) & 0x8000)) return FALSE
;
1410 width
= get_system_metrics( SM_CXDRAG
);
1411 height
= get_system_metrics( SM_CYDRAG
);
1412 SetRect( &rect
, x
- width
, y
- height
, x
+ width
, y
+ height
);
1414 NtUserSetCapture( hwnd
);
1418 while (NtUserPeekMessage( &msg
, 0, WM_MOUSEFIRST
, WM_MOUSELAST
, PM_REMOVE
))
1420 if (msg
.message
== WM_LBUTTONUP
)
1425 if (msg
.message
== WM_MOUSEMOVE
)
1428 tmp
.x
= (short)LOWORD( msg
.lParam
);
1429 tmp
.y
= (short)HIWORD( msg
.lParam
);
1430 if (!PtInRect( &rect
, tmp
))
1437 NtUserMsgWaitForMultipleObjectsEx( 0, NULL
, INFINITE
, QS_ALLINPUT
, 0 );
1442 /**********************************************************************
1443 * set_capture_window
1445 BOOL
set_capture_window( HWND hwnd
, UINT gui_flags
, HWND
*prev_ret
)
1451 if (gui_flags
& GUI_INMENUMODE
) flags
|= CAPTURE_MENU
;
1452 if (gui_flags
& GUI_INMOVESIZE
) flags
|= CAPTURE_MOVESIZE
;
1454 SERVER_START_REQ( set_capture_window
)
1456 req
->handle
= wine_server_user_handle( hwnd
);
1458 if ((ret
= !wine_server_call_err( req
)))
1460 previous
= wine_server_ptr_handle( reply
->previous
);
1461 hwnd
= wine_server_ptr_handle( reply
->full_handle
);
1468 user_driver
->pSetCapture( hwnd
, gui_flags
);
1471 send_message( previous
, WM_CAPTURECHANGED
, 0, (LPARAM
)hwnd
);
1473 if (prev_ret
) *prev_ret
= previous
;
1478 /**********************************************************************
1479 * NtUserSetCapture (win32u.@)
1481 HWND WINAPI
NtUserSetCapture( HWND hwnd
)
1485 set_capture_window( hwnd
, 0, &previous
);
1489 /**********************************************************************
1492 BOOL WINAPI
release_capture(void)
1494 BOOL ret
= set_capture_window( 0, 0, NULL
);
1496 /* Somebody may have missed some mouse movements */
1499 INPUT input
= { .type
= INPUT_MOUSE
};
1500 input
.mi
.dwFlags
= MOUSEEVENTF_MOVE
;
1501 NtUserSendInput( 1, &input
, sizeof(input
) );
1507 /*******************************************************************
1508 * NtUserGetForegroundWindow (win32u.@)
1510 HWND WINAPI
NtUserGetForegroundWindow(void)
1514 SERVER_START_REQ( get_thread_input
)
1517 if (!wine_server_call_err( req
)) ret
= wine_server_ptr_handle( reply
->foreground
);
1523 /* see GetActiveWindow */
1524 HWND
get_active_window(void)
1527 info
.cbSize
= sizeof(info
);
1528 return NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info
) ? info
.hwndActive
: 0;
1531 /* see GetCapture */
1532 HWND
get_capture(void)
1535 info
.cbSize
= sizeof(info
);
1536 return NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info
) ? info
.hwndCapture
: 0;
1540 HWND
get_focus(void)
1543 info
.cbSize
= sizeof(info
);
1544 return NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info
) ? info
.hwndFocus
: 0;
1547 /*****************************************************************
1550 * Change the focus window, sending the WM_SETFOCUS and WM_KILLFOCUS messages
1552 static HWND
set_focus_window( HWND hwnd
)
1554 HWND previous
= 0, ime_hwnd
;
1557 SERVER_START_REQ( set_focus_window
)
1559 req
->handle
= wine_server_user_handle( hwnd
);
1560 if ((ret
= !wine_server_call_err( req
)))
1561 previous
= wine_server_ptr_handle( reply
->previous
);
1565 if (previous
== hwnd
) return previous
;
1569 send_message( previous
, WM_KILLFOCUS
, (WPARAM
)hwnd
, 0 );
1571 ime_hwnd
= get_default_ime_window( previous
);
1573 send_message( ime_hwnd
, WM_IME_INTERNAL
, IME_INTERNAL_DEACTIVATE
,
1574 HandleToUlong(previous
) );
1576 if (hwnd
!= get_focus()) return previous
; /* changed by the message */
1578 if (is_window(hwnd
))
1580 user_driver
->pSetFocus(hwnd
);
1582 ime_hwnd
= get_default_ime_window( hwnd
);
1584 send_message( ime_hwnd
, WM_IME_INTERNAL
, IME_INTERNAL_ACTIVATE
,
1585 HandleToUlong(hwnd
) );
1588 NtUserNotifyWinEvent( EVENT_OBJECT_FOCUS
, hwnd
, OBJID_CLIENT
, 0 );
1590 send_message( hwnd
, WM_SETFOCUS
, (WPARAM
)previous
, 0 );
1595 /*******************************************************************
1598 static BOOL
set_active_window( HWND hwnd
, HWND
*prev
, BOOL mouse
, BOOL focus
)
1600 HWND previous
= get_active_window();
1602 DWORD old_thread
, new_thread
;
1603 CBTACTIVATESTRUCT cbt
;
1605 if (previous
== hwnd
)
1607 if (prev
) *prev
= hwnd
;
1611 /* call CBT hook chain */
1613 cbt
.hWndActive
= previous
;
1614 if (call_hooks( WH_CBT
, HCBT_ACTIVATE
, (WPARAM
)hwnd
, (LPARAM
)&cbt
, sizeof(cbt
) )) return FALSE
;
1616 if (is_window( previous
))
1618 send_message( previous
, WM_NCACTIVATE
, FALSE
, (LPARAM
)hwnd
);
1619 send_message( previous
, WM_ACTIVATE
,
1620 MAKEWPARAM( WA_INACTIVE
, is_iconic(previous
) ), (LPARAM
)hwnd
);
1623 SERVER_START_REQ( set_active_window
)
1625 req
->handle
= wine_server_user_handle( hwnd
);
1626 if ((ret
= !wine_server_call_err( req
)))
1627 previous
= wine_server_ptr_handle( reply
->previous
);
1630 if (!ret
) return FALSE
;
1631 if (prev
) *prev
= previous
;
1632 if (previous
== hwnd
) return TRUE
;
1636 /* send palette messages */
1637 if (send_message( hwnd
, WM_QUERYNEWPALETTE
, 0, 0 ))
1638 send_message_timeout( HWND_BROADCAST
, WM_PALETTEISCHANGING
, (WPARAM
)hwnd
, 0,
1639 SMTO_ABORTIFHUNG
, 2000, FALSE
);
1640 if (!is_window(hwnd
)) return FALSE
;
1643 old_thread
= previous
? get_window_thread( previous
, NULL
) : 0;
1644 new_thread
= hwnd
? get_window_thread( hwnd
, NULL
) : 0;
1646 if (old_thread
!= new_thread
)
1650 if ((list
= list_window_children( NULL
, get_desktop_window(), NULL
, 0 )))
1654 for (phwnd
= list
; *phwnd
; phwnd
++)
1656 if (get_window_thread( *phwnd
, NULL
) == old_thread
)
1657 send_message( *phwnd
, WM_ACTIVATEAPP
, 0, new_thread
);
1662 for (phwnd
= list
; *phwnd
; phwnd
++)
1664 if (get_window_thread( *phwnd
, NULL
) == new_thread
)
1665 send_message( *phwnd
, WM_ACTIVATEAPP
, 1, old_thread
);
1672 if (is_window(hwnd
))
1674 send_message( hwnd
, WM_NCACTIVATE
, hwnd
== NtUserGetForegroundWindow(), (LPARAM
)previous
);
1675 send_message( hwnd
, WM_ACTIVATE
,
1676 MAKEWPARAM( mouse
? WA_CLICKACTIVE
: WA_ACTIVE
, is_iconic(hwnd
) ),
1678 if (NtUserGetAncestor( hwnd
, GA_PARENT
) == get_desktop_window())
1679 NtUserPostMessage( get_desktop_window(), WM_PARENTNOTIFY
, WM_NCACTIVATE
, (LPARAM
)hwnd
);
1682 /* now change focus if necessary */
1687 info
.cbSize
= sizeof(info
);
1688 NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info
);
1689 /* Do not change focus if the window is no more active */
1690 if (hwnd
== info
.hwndActive
)
1692 if (!info
.hwndFocus
|| !hwnd
|| NtUserGetAncestor( info
.hwndFocus
, GA_ROOT
) != hwnd
)
1693 set_focus_window( hwnd
);
1700 /**********************************************************************
1701 * NtUserSetActiveWindow (win32u.@)
1703 HWND WINAPI
NtUserSetActiveWindow( HWND hwnd
)
1707 TRACE( "%p\n", hwnd
);
1713 hwnd
= get_full_window_handle( hwnd
);
1714 if (!is_window( hwnd
))
1716 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
1720 style
= get_window_long( hwnd
, GWL_STYLE
);
1721 if ((style
& (WS_POPUP
|WS_CHILD
)) == WS_CHILD
)
1722 return get_active_window(); /* Windows doesn't seem to return an error here */
1725 if (!set_active_window( hwnd
, &prev
, FALSE
, TRUE
)) return 0;
1729 /*****************************************************************
1730 * NtUserSetFocus (win32u.@)
1732 HWND WINAPI
NtUserSetFocus( HWND hwnd
)
1734 HWND hwndTop
= hwnd
;
1735 HWND previous
= get_focus();
1737 TRACE( "%p prev %p\n", hwnd
, previous
);
1741 /* Check if we can set the focus to this window */
1742 hwnd
= get_full_window_handle( hwnd
);
1743 if (!is_window( hwnd
))
1745 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
1748 if (hwnd
== previous
) return previous
; /* nothing to do */
1752 LONG style
= get_window_long( hwndTop
, GWL_STYLE
);
1753 if (style
& (WS_MINIMIZE
| WS_DISABLED
)) return 0;
1754 if (!(style
& WS_CHILD
)) break;
1755 parent
= NtUserGetAncestor( hwndTop
, GA_PARENT
);
1756 if (!parent
|| parent
== get_desktop_window())
1758 if ((style
& (WS_POPUP
|WS_CHILD
)) == WS_CHILD
) return 0;
1761 if (parent
== get_hwnd_message_parent()) return 0;
1766 if (call_hooks( WH_CBT
, HCBT_SETFOCUS
, (WPARAM
)hwnd
, (LPARAM
)previous
, 0 )) return 0;
1768 /* activate hwndTop if needed. */
1769 if (hwndTop
!= get_active_window())
1771 if (!set_active_window( hwndTop
, NULL
, FALSE
, FALSE
)) return 0;
1772 if (!is_window( hwnd
)) return 0; /* Abort if window destroyed */
1774 /* Do not change focus if the window is no longer active */
1775 if (hwndTop
!= get_active_window()) return 0;
1778 else /* NULL hwnd passed in */
1780 if (!previous
) return 0; /* nothing to do */
1781 if (call_hooks( WH_CBT
, HCBT_SETFOCUS
, 0, (LPARAM
)previous
, 0 )) return 0;
1784 /* change focus and send messages */
1785 return set_focus_window( hwnd
);
1788 /*******************************************************************
1789 * set_foreground_window
1791 BOOL
set_foreground_window( HWND hwnd
, BOOL mouse
)
1793 BOOL ret
, send_msg_old
= FALSE
, send_msg_new
= FALSE
;
1796 if (mouse
) hwnd
= get_full_window_handle( hwnd
);
1798 SERVER_START_REQ( set_foreground_window
)
1800 req
->handle
= wine_server_user_handle( hwnd
);
1801 if ((ret
= !wine_server_call_err( req
)))
1803 previous
= wine_server_ptr_handle( reply
->previous
);
1804 send_msg_old
= reply
->send_msg_old
;
1805 send_msg_new
= reply
->send_msg_new
;
1810 if (ret
&& previous
!= hwnd
)
1812 if (send_msg_old
) /* old window belongs to other thread */
1813 NtUserMessageCall( previous
, WM_WINE_SETACTIVEWINDOW
, 0, 0,
1814 0, NtUserSendNotifyMessage
, FALSE
);
1815 else if (send_msg_new
) /* old window belongs to us but new one to other thread */
1816 ret
= set_active_window( 0, NULL
, mouse
, TRUE
);
1818 if (send_msg_new
) /* new window belongs to other thread */
1819 NtUserMessageCall( hwnd
, WM_WINE_SETACTIVEWINDOW
, (WPARAM
)hwnd
, 0,
1820 0, NtUserSendNotifyMessage
, FALSE
);
1821 else /* new window belongs to us */
1822 ret
= set_active_window( hwnd
, NULL
, mouse
, TRUE
);
1830 unsigned int timeout
;
1833 static void display_caret( HWND hwnd
, const RECT
*r
)
1837 /* do not use DCX_CACHE here, since coördinates are in logical units */
1838 if (!(dc
= NtUserGetDCEx( hwnd
, 0, DCX_USESTYLE
)))
1840 mem_dc
= NtGdiCreateCompatibleDC(dc
);
1843 HBITMAP prev_bitmap
;
1845 prev_bitmap
= NtGdiSelectBitmap( mem_dc
, caret
.bitmap
);
1846 NtGdiBitBlt( dc
, r
->left
, r
->top
, r
->right
-r
->left
, r
->bottom
-r
->top
, mem_dc
, 0, 0, SRCINVERT
, 0, 0 );
1847 NtGdiSelectBitmap( mem_dc
, prev_bitmap
);
1848 NtGdiDeleteObjectApp( mem_dc
);
1850 NtUserReleaseDC( hwnd
, dc
);
1853 static unsigned int get_caret_registry_timeout(void)
1855 char value_buffer
[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[11 * sizeof(WCHAR
)])];
1856 KEY_VALUE_PARTIAL_INFORMATION
*value
= (void *)value_buffer
;
1857 unsigned int ret
= 500;
1860 if (!(key
= reg_open_hkcu_key( "Control Panel\\Desktop" )))
1863 if (query_reg_ascii_value( key
, "CursorBlinkRate", value
, sizeof(value_buffer
) ))
1864 ret
= wcstoul( (WCHAR
*)value
->Data
, NULL
, 10 );
1869 /*****************************************************************
1870 * NtUserCreateCaret (win32u.@)
1872 BOOL WINAPI
NtUserCreateCaret( HWND hwnd
, HBITMAP bitmap
, int width
, int height
)
1874 HBITMAP caret_bitmap
= 0;
1881 TRACE( "hwnd %p, bitmap %p, width %d, height %d\n", hwnd
, bitmap
, width
, height
);
1883 if (!hwnd
) return FALSE
;
1885 if (bitmap
&& bitmap
!= (HBITMAP
)1)
1889 if (!NtGdiExtGetObjectW( bitmap
, sizeof(bitmap_data
), &bitmap_data
)) return FALSE
;
1890 caret_bitmap
= NtGdiCreateBitmap( bitmap_data
.bmWidth
, bitmap_data
.bmHeight
,
1891 bitmap_data
.bmPlanes
, bitmap_data
.bmBitsPixel
, NULL
);
1894 size_t size
= bitmap_data
.bmWidthBytes
* bitmap_data
.bmHeight
;
1895 BYTE
*bits
= malloc( size
);
1897 NtGdiGetBitmapBits( bitmap
, size
, bits
);
1898 NtGdiSetBitmapBits( caret_bitmap
, size
, bits
);
1906 if (!width
) width
= get_system_metrics( SM_CXBORDER
);
1907 if (!height
) height
= get_system_metrics( SM_CYBORDER
);
1909 /* create the uniform bitmap on the fly */
1910 dc
= NtUserGetDCEx( hwnd
, 0, DCX_USESTYLE
);
1913 HDC mem_dc
= NtGdiCreateCompatibleDC( dc
);
1916 if ((caret_bitmap
= NtGdiCreateCompatibleBitmap( mem_dc
, width
, height
)))
1918 HBITMAP prev_bitmap
= NtGdiSelectBitmap( mem_dc
, caret_bitmap
);
1919 SetRect( &r
, 0, 0, width
, height
);
1920 fill_rect( mem_dc
, &r
, GetStockObject( bitmap
? GRAY_BRUSH
: WHITE_BRUSH
));
1921 NtGdiSelectBitmap( mem_dc
, prev_bitmap
);
1923 NtGdiDeleteObjectApp( mem_dc
);
1925 NtUserReleaseDC( hwnd
, dc
);
1928 if (!caret_bitmap
) return FALSE
;
1930 SERVER_START_REQ( set_caret_window
)
1932 req
->handle
= wine_server_user_handle( hwnd
);
1934 req
->height
= height
;
1935 if ((ret
= !wine_server_call_err( req
)))
1937 prev
= wine_server_ptr_handle( reply
->previous
);
1938 r
.left
= reply
->old_rect
.left
;
1939 r
.top
= reply
->old_rect
.top
;
1940 r
.right
= reply
->old_rect
.right
;
1941 r
.bottom
= reply
->old_rect
.bottom
;
1942 old_state
= reply
->old_state
;
1943 hidden
= reply
->old_hide
;
1947 if (!ret
) return FALSE
;
1949 if (prev
&& !hidden
) /* hide the previous one */
1951 /* FIXME: won't work if prev belongs to a different process */
1952 kill_system_timer( prev
, SYSTEM_TIMER_CARET
);
1953 if (old_state
) display_caret( prev
, &r
);
1956 if (caret
.bitmap
) NtGdiDeleteObjectApp( caret
.bitmap
);
1957 caret
.bitmap
= caret_bitmap
;
1958 caret
.timeout
= get_caret_registry_timeout();
1962 /*******************************************************************
1965 BOOL
destroy_caret(void)
1973 SERVER_START_REQ( set_caret_window
)
1978 if ((ret
= !wine_server_call_err( req
)))
1980 prev
= wine_server_ptr_handle( reply
->previous
);
1981 r
.left
= reply
->old_rect
.left
;
1982 r
.top
= reply
->old_rect
.top
;
1983 r
.right
= reply
->old_rect
.right
;
1984 r
.bottom
= reply
->old_rect
.bottom
;
1985 old_state
= reply
->old_state
;
1986 hidden
= reply
->old_hide
;
1991 if (ret
&& prev
&& !hidden
)
1993 /* FIXME: won't work if prev belongs to a different process */
1994 kill_system_timer( prev
, SYSTEM_TIMER_CARET
);
1995 if (old_state
) display_caret( prev
, &r
);
1997 if (caret
.bitmap
) NtGdiDeleteObjectApp( caret
.bitmap
);
2002 /*****************************************************************
2003 * NtUserGetCaretBlinkTime (win32u.@)
2005 UINT WINAPI
NtUserGetCaretBlinkTime(void)
2007 return caret
.timeout
;
2010 /*******************************************************************
2011 * set_caret_blink_time
2013 BOOL
set_caret_blink_time( unsigned int time
)
2015 TRACE( "time %u\n", time
);
2017 caret
.timeout
= time
;
2018 /* FIXME: update the timer */
2022 /*****************************************************************
2023 * NtUserGetCaretPos (win32u.@)
2025 BOOL WINAPI
NtUserGetCaretPos( POINT
*pt
)
2029 SERVER_START_REQ( set_caret_info
)
2031 req
->flags
= 0; /* don't set anything */
2037 if ((ret
= !wine_server_call_err( req
)))
2039 pt
->x
= reply
->old_rect
.left
;
2040 pt
->y
= reply
->old_rect
.top
;
2047 /*******************************************************************
2050 BOOL
set_caret_pos( int x
, int y
)
2058 TRACE( "(%d, %d)\n", x
, y
);
2060 SERVER_START_REQ( set_caret_info
)
2062 req
->flags
= SET_CARET_POS
|SET_CARET_STATE
;
2067 req
->state
= CARET_STATE_ON_IF_MOVED
;
2068 if ((ret
= !wine_server_call_err( req
)))
2070 hwnd
= wine_server_ptr_handle( reply
->full_handle
);
2071 r
.left
= reply
->old_rect
.left
;
2072 r
.top
= reply
->old_rect
.top
;
2073 r
.right
= reply
->old_rect
.right
;
2074 r
.bottom
= reply
->old_rect
.bottom
;
2075 old_state
= reply
->old_state
;
2076 hidden
= reply
->old_hide
;
2080 if (ret
&& !hidden
&& (x
!= r
.left
|| y
!= r
.top
))
2082 if (old_state
) display_caret( hwnd
, &r
);
2083 r
.right
+= x
- r
.left
;
2084 r
.bottom
+= y
- r
.top
;
2087 display_caret( hwnd
, &r
);
2088 NtUserSetSystemTimer( hwnd
, SYSTEM_TIMER_CARET
, caret
.timeout
);
2093 /*****************************************************************
2094 * NtUserShowCaret (win32u.@)
2096 BOOL WINAPI
NtUserShowCaret( HWND hwnd
)
2102 SERVER_START_REQ( set_caret_info
)
2104 req
->flags
= SET_CARET_HIDE
| SET_CARET_STATE
;
2105 req
->handle
= wine_server_user_handle( hwnd
);
2109 req
->state
= CARET_STATE_ON
;
2110 if ((ret
= !wine_server_call_err( req
)))
2112 hwnd
= wine_server_ptr_handle( reply
->full_handle
);
2113 r
.left
= reply
->old_rect
.left
;
2114 r
.top
= reply
->old_rect
.top
;
2115 r
.right
= reply
->old_rect
.right
;
2116 r
.bottom
= reply
->old_rect
.bottom
;
2117 hidden
= reply
->old_hide
;
2122 if (ret
&& hidden
== 1) /* hidden was 1 so it's now 0 */
2124 display_caret( hwnd
, &r
);
2125 NtUserSetSystemTimer( hwnd
, SYSTEM_TIMER_CARET
, caret
.timeout
);
2130 /*****************************************************************
2131 * NtUserHideCaret (win32u.@)
2133 BOOL WINAPI
NtUserHideCaret( HWND hwnd
)
2140 SERVER_START_REQ( set_caret_info
)
2142 req
->flags
= SET_CARET_HIDE
| SET_CARET_STATE
;
2143 req
->handle
= wine_server_user_handle( hwnd
);
2147 req
->state
= CARET_STATE_OFF
;
2148 if ((ret
= !wine_server_call_err( req
)))
2150 hwnd
= wine_server_ptr_handle( reply
->full_handle
);
2151 r
.left
= reply
->old_rect
.left
;
2152 r
.top
= reply
->old_rect
.top
;
2153 r
.right
= reply
->old_rect
.right
;
2154 r
.bottom
= reply
->old_rect
.bottom
;
2155 old_state
= reply
->old_state
;
2156 hidden
= reply
->old_hide
;
2163 if (old_state
) display_caret( hwnd
, &r
);
2164 kill_system_timer( hwnd
, SYSTEM_TIMER_CARET
);
2169 void toggle_caret( HWND hwnd
)
2175 SERVER_START_REQ( set_caret_info
)
2177 req
->flags
= SET_CARET_STATE
;
2178 req
->handle
= wine_server_user_handle( hwnd
);
2182 req
->state
= CARET_STATE_TOGGLE
;
2183 if ((ret
= !wine_server_call( req
)))
2185 hwnd
= wine_server_ptr_handle( reply
->full_handle
);
2186 r
.left
= reply
->old_rect
.left
;
2187 r
.top
= reply
->old_rect
.top
;
2188 r
.right
= reply
->old_rect
.right
;
2189 r
.bottom
= reply
->old_rect
.bottom
;
2190 hidden
= reply
->old_hide
;
2195 if (ret
&& !hidden
) display_caret( hwnd
, &r
);