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 * set_capture_window
1400 BOOL
set_capture_window( HWND hwnd
, UINT gui_flags
, HWND
*prev_ret
)
1406 if (gui_flags
& GUI_INMENUMODE
) flags
|= CAPTURE_MENU
;
1407 if (gui_flags
& GUI_INMOVESIZE
) flags
|= CAPTURE_MOVESIZE
;
1409 SERVER_START_REQ( set_capture_window
)
1411 req
->handle
= wine_server_user_handle( hwnd
);
1413 if ((ret
= !wine_server_call_err( req
)))
1415 previous
= wine_server_ptr_handle( reply
->previous
);
1416 hwnd
= wine_server_ptr_handle( reply
->full_handle
);
1423 user_driver
->pSetCapture( hwnd
, gui_flags
);
1426 send_message( previous
, WM_CAPTURECHANGED
, 0, (LPARAM
)hwnd
);
1428 if (prev_ret
) *prev_ret
= previous
;
1433 /**********************************************************************
1434 * NtUserSetCapture (win32u.@)
1436 HWND WINAPI
NtUserSetCapture( HWND hwnd
)
1440 set_capture_window( hwnd
, 0, &previous
);
1444 /**********************************************************************
1447 BOOL WINAPI
release_capture(void)
1449 BOOL ret
= set_capture_window( 0, 0, NULL
);
1451 /* Somebody may have missed some mouse movements */
1454 INPUT input
= { .type
= INPUT_MOUSE
};
1455 input
.mi
.dwFlags
= MOUSEEVENTF_MOVE
;
1456 NtUserSendInput( 1, &input
, sizeof(input
) );
1462 /*******************************************************************
1463 * NtUserGetForegroundWindow (win32u.@)
1465 HWND WINAPI
NtUserGetForegroundWindow(void)
1469 SERVER_START_REQ( get_thread_input
)
1472 if (!wine_server_call_err( req
)) ret
= wine_server_ptr_handle( reply
->foreground
);
1478 /* see GetActiveWindow */
1479 HWND
get_active_window(void)
1482 info
.cbSize
= sizeof(info
);
1483 return NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info
) ? info
.hwndActive
: 0;
1486 /* see GetCapture */
1487 HWND
get_capture(void)
1490 info
.cbSize
= sizeof(info
);
1491 return NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info
) ? info
.hwndCapture
: 0;
1495 HWND
get_focus(void)
1498 info
.cbSize
= sizeof(info
);
1499 return NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info
) ? info
.hwndFocus
: 0;
1502 /*****************************************************************
1505 * Change the focus window, sending the WM_SETFOCUS and WM_KILLFOCUS messages
1507 static HWND
set_focus_window( HWND hwnd
)
1509 HWND previous
= 0, ime_hwnd
;
1512 SERVER_START_REQ( set_focus_window
)
1514 req
->handle
= wine_server_user_handle( hwnd
);
1515 if ((ret
= !wine_server_call_err( req
)))
1516 previous
= wine_server_ptr_handle( reply
->previous
);
1520 if (previous
== hwnd
) return previous
;
1524 send_message( previous
, WM_KILLFOCUS
, (WPARAM
)hwnd
, 0 );
1526 ime_hwnd
= get_default_ime_window( previous
);
1528 send_message( ime_hwnd
, WM_IME_INTERNAL
, IME_INTERNAL_DEACTIVATE
,
1529 HandleToUlong(previous
) );
1531 if (hwnd
!= get_focus()) return previous
; /* changed by the message */
1533 if (is_window(hwnd
))
1535 user_driver
->pSetFocus(hwnd
);
1537 ime_hwnd
= get_default_ime_window( hwnd
);
1539 send_message( ime_hwnd
, WM_IME_INTERNAL
, IME_INTERNAL_ACTIVATE
,
1540 HandleToUlong(hwnd
) );
1543 NtUserNotifyWinEvent( EVENT_OBJECT_FOCUS
, hwnd
, OBJID_CLIENT
, 0 );
1545 send_message( hwnd
, WM_SETFOCUS
, (WPARAM
)previous
, 0 );
1550 /*******************************************************************
1553 static BOOL
set_active_window( HWND hwnd
, HWND
*prev
, BOOL mouse
, BOOL focus
)
1555 HWND previous
= get_active_window();
1557 DWORD old_thread
, new_thread
;
1558 CBTACTIVATESTRUCT cbt
;
1560 if (previous
== hwnd
)
1562 if (prev
) *prev
= hwnd
;
1566 /* call CBT hook chain */
1568 cbt
.hWndActive
= previous
;
1569 if (call_hooks( WH_CBT
, HCBT_ACTIVATE
, (WPARAM
)hwnd
, (LPARAM
)&cbt
, sizeof(cbt
) )) return FALSE
;
1571 if (is_window( previous
))
1573 send_message( previous
, WM_NCACTIVATE
, FALSE
, (LPARAM
)hwnd
);
1574 send_message( previous
, WM_ACTIVATE
,
1575 MAKEWPARAM( WA_INACTIVE
, is_iconic(previous
) ), (LPARAM
)hwnd
);
1578 SERVER_START_REQ( set_active_window
)
1580 req
->handle
= wine_server_user_handle( hwnd
);
1581 if ((ret
= !wine_server_call_err( req
)))
1582 previous
= wine_server_ptr_handle( reply
->previous
);
1585 if (!ret
) return FALSE
;
1586 if (prev
) *prev
= previous
;
1587 if (previous
== hwnd
) return TRUE
;
1591 /* send palette messages */
1592 if (send_message( hwnd
, WM_QUERYNEWPALETTE
, 0, 0 ))
1593 send_message_timeout( HWND_BROADCAST
, WM_PALETTEISCHANGING
, (WPARAM
)hwnd
, 0,
1594 SMTO_ABORTIFHUNG
, 2000, FALSE
);
1595 if (!is_window(hwnd
)) return FALSE
;
1598 old_thread
= previous
? get_window_thread( previous
, NULL
) : 0;
1599 new_thread
= hwnd
? get_window_thread( hwnd
, NULL
) : 0;
1601 if (old_thread
!= new_thread
)
1605 if ((list
= list_window_children( NULL
, get_desktop_window(), NULL
, 0 )))
1609 for (phwnd
= list
; *phwnd
; phwnd
++)
1611 if (get_window_thread( *phwnd
, NULL
) == old_thread
)
1612 send_message( *phwnd
, WM_ACTIVATEAPP
, 0, new_thread
);
1617 for (phwnd
= list
; *phwnd
; phwnd
++)
1619 if (get_window_thread( *phwnd
, NULL
) == new_thread
)
1620 send_message( *phwnd
, WM_ACTIVATEAPP
, 1, old_thread
);
1627 if (is_window(hwnd
))
1629 send_message( hwnd
, WM_NCACTIVATE
, hwnd
== NtUserGetForegroundWindow(), (LPARAM
)previous
);
1630 send_message( hwnd
, WM_ACTIVATE
,
1631 MAKEWPARAM( mouse
? WA_CLICKACTIVE
: WA_ACTIVE
, is_iconic(hwnd
) ),
1633 if (NtUserGetAncestor( hwnd
, GA_PARENT
) == get_desktop_window())
1634 NtUserPostMessage( get_desktop_window(), WM_PARENTNOTIFY
, WM_NCACTIVATE
, (LPARAM
)hwnd
);
1637 /* now change focus if necessary */
1642 info
.cbSize
= sizeof(info
);
1643 NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info
);
1644 /* Do not change focus if the window is no more active */
1645 if (hwnd
== info
.hwndActive
)
1647 if (!info
.hwndFocus
|| !hwnd
|| NtUserGetAncestor( info
.hwndFocus
, GA_ROOT
) != hwnd
)
1648 set_focus_window( hwnd
);
1655 /**********************************************************************
1656 * NtUserSetActiveWindow (win32u.@)
1658 HWND WINAPI
NtUserSetActiveWindow( HWND hwnd
)
1662 TRACE( "%p\n", hwnd
);
1668 hwnd
= get_full_window_handle( hwnd
);
1669 if (!is_window( hwnd
))
1671 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
1675 style
= get_window_long( hwnd
, GWL_STYLE
);
1676 if ((style
& (WS_POPUP
|WS_CHILD
)) == WS_CHILD
)
1677 return get_active_window(); /* Windows doesn't seem to return an error here */
1680 if (!set_active_window( hwnd
, &prev
, FALSE
, TRUE
)) return 0;
1684 /*****************************************************************
1685 * NtUserSetFocus (win32u.@)
1687 HWND WINAPI
NtUserSetFocus( HWND hwnd
)
1689 HWND hwndTop
= hwnd
;
1690 HWND previous
= get_focus();
1692 TRACE( "%p prev %p\n", hwnd
, previous
);
1696 /* Check if we can set the focus to this window */
1697 hwnd
= get_full_window_handle( hwnd
);
1698 if (!is_window( hwnd
))
1700 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
1703 if (hwnd
== previous
) return previous
; /* nothing to do */
1707 LONG style
= get_window_long( hwndTop
, GWL_STYLE
);
1708 if (style
& (WS_MINIMIZE
| WS_DISABLED
)) return 0;
1709 if (!(style
& WS_CHILD
)) break;
1710 parent
= NtUserGetAncestor( hwndTop
, GA_PARENT
);
1711 if (!parent
|| parent
== get_desktop_window())
1713 if ((style
& (WS_POPUP
|WS_CHILD
)) == WS_CHILD
) return 0;
1716 if (parent
== get_hwnd_message_parent()) return 0;
1721 if (call_hooks( WH_CBT
, HCBT_SETFOCUS
, (WPARAM
)hwnd
, (LPARAM
)previous
, 0 )) return 0;
1723 /* activate hwndTop if needed. */
1724 if (hwndTop
!= get_active_window())
1726 if (!set_active_window( hwndTop
, NULL
, FALSE
, FALSE
)) return 0;
1727 if (!is_window( hwnd
)) return 0; /* Abort if window destroyed */
1729 /* Do not change focus if the window is no longer active */
1730 if (hwndTop
!= get_active_window()) return 0;
1733 else /* NULL hwnd passed in */
1735 if (!previous
) return 0; /* nothing to do */
1736 if (call_hooks( WH_CBT
, HCBT_SETFOCUS
, 0, (LPARAM
)previous
, 0 )) return 0;
1739 /* change focus and send messages */
1740 return set_focus_window( hwnd
);
1743 /*******************************************************************
1744 * set_foreground_window
1746 BOOL
set_foreground_window( HWND hwnd
, BOOL mouse
)
1748 BOOL ret
, send_msg_old
= FALSE
, send_msg_new
= FALSE
;
1751 if (mouse
) hwnd
= get_full_window_handle( hwnd
);
1753 SERVER_START_REQ( set_foreground_window
)
1755 req
->handle
= wine_server_user_handle( hwnd
);
1756 if ((ret
= !wine_server_call_err( req
)))
1758 previous
= wine_server_ptr_handle( reply
->previous
);
1759 send_msg_old
= reply
->send_msg_old
;
1760 send_msg_new
= reply
->send_msg_new
;
1765 if (ret
&& previous
!= hwnd
)
1767 if (send_msg_old
) /* old window belongs to other thread */
1768 NtUserMessageCall( previous
, WM_WINE_SETACTIVEWINDOW
, 0, 0,
1769 0, NtUserSendNotifyMessage
, FALSE
);
1770 else if (send_msg_new
) /* old window belongs to us but new one to other thread */
1771 ret
= set_active_window( 0, NULL
, mouse
, TRUE
);
1773 if (send_msg_new
) /* new window belongs to other thread */
1774 NtUserMessageCall( hwnd
, WM_WINE_SETACTIVEWINDOW
, (WPARAM
)hwnd
, 0,
1775 0, NtUserSendNotifyMessage
, FALSE
);
1776 else /* new window belongs to us */
1777 ret
= set_active_window( hwnd
, NULL
, mouse
, TRUE
);
1785 unsigned int timeout
;
1788 static void display_caret( HWND hwnd
, const RECT
*r
)
1792 /* do not use DCX_CACHE here, since coördinates are in logical units */
1793 if (!(dc
= NtUserGetDCEx( hwnd
, 0, DCX_USESTYLE
)))
1795 mem_dc
= NtGdiCreateCompatibleDC(dc
);
1798 HBITMAP prev_bitmap
;
1800 prev_bitmap
= NtGdiSelectBitmap( mem_dc
, caret
.bitmap
);
1801 NtGdiBitBlt( dc
, r
->left
, r
->top
, r
->right
-r
->left
, r
->bottom
-r
->top
, mem_dc
, 0, 0, SRCINVERT
, 0, 0 );
1802 NtGdiSelectBitmap( mem_dc
, prev_bitmap
);
1803 NtGdiDeleteObjectApp( mem_dc
);
1805 NtUserReleaseDC( hwnd
, dc
);
1808 static unsigned int get_caret_registry_timeout(void)
1810 char value_buffer
[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[11 * sizeof(WCHAR
)])];
1811 KEY_VALUE_PARTIAL_INFORMATION
*value
= (void *)value_buffer
;
1812 unsigned int ret
= 500;
1815 if (!(key
= reg_open_hkcu_key( "Control Panel\\Desktop" )))
1818 if (query_reg_ascii_value( key
, "CursorBlinkRate", value
, sizeof(value_buffer
) ))
1819 ret
= wcstoul( (WCHAR
*)value
->Data
, NULL
, 10 );
1824 /*****************************************************************
1825 * NtUserCreateCaret (win32u.@)
1827 BOOL WINAPI
NtUserCreateCaret( HWND hwnd
, HBITMAP bitmap
, int width
, int height
)
1829 HBITMAP caret_bitmap
= 0;
1836 TRACE( "hwnd %p, bitmap %p, width %d, height %d\n", hwnd
, bitmap
, width
, height
);
1838 if (!hwnd
) return FALSE
;
1840 if (bitmap
&& bitmap
!= (HBITMAP
)1)
1844 if (!NtGdiExtGetObjectW( bitmap
, sizeof(bitmap_data
), &bitmap_data
)) return FALSE
;
1845 caret_bitmap
= NtGdiCreateBitmap( bitmap_data
.bmWidth
, bitmap_data
.bmHeight
,
1846 bitmap_data
.bmPlanes
, bitmap_data
.bmBitsPixel
, NULL
);
1849 size_t size
= bitmap_data
.bmWidthBytes
* bitmap_data
.bmHeight
;
1850 BYTE
*bits
= malloc( size
);
1852 NtGdiGetBitmapBits( bitmap
, size
, bits
);
1853 NtGdiSetBitmapBits( caret_bitmap
, size
, bits
);
1861 if (!width
) width
= get_system_metrics( SM_CXBORDER
);
1862 if (!height
) height
= get_system_metrics( SM_CYBORDER
);
1864 /* create the uniform bitmap on the fly */
1865 dc
= NtUserGetDCEx( hwnd
, 0, DCX_USESTYLE
);
1868 HDC mem_dc
= NtGdiCreateCompatibleDC( dc
);
1871 if ((caret_bitmap
= NtGdiCreateCompatibleBitmap( mem_dc
, width
, height
)))
1873 HBITMAP prev_bitmap
= NtGdiSelectBitmap( mem_dc
, caret_bitmap
);
1874 SetRect( &r
, 0, 0, width
, height
);
1875 fill_rect( mem_dc
, &r
, GetStockObject( bitmap
? GRAY_BRUSH
: WHITE_BRUSH
));
1876 NtGdiSelectBitmap( mem_dc
, prev_bitmap
);
1878 NtGdiDeleteObjectApp( mem_dc
);
1880 NtUserReleaseDC( hwnd
, dc
);
1883 if (!caret_bitmap
) return FALSE
;
1885 SERVER_START_REQ( set_caret_window
)
1887 req
->handle
= wine_server_user_handle( hwnd
);
1889 req
->height
= height
;
1890 if ((ret
= !wine_server_call_err( req
)))
1892 prev
= wine_server_ptr_handle( reply
->previous
);
1893 r
.left
= reply
->old_rect
.left
;
1894 r
.top
= reply
->old_rect
.top
;
1895 r
.right
= reply
->old_rect
.right
;
1896 r
.bottom
= reply
->old_rect
.bottom
;
1897 old_state
= reply
->old_state
;
1898 hidden
= reply
->old_hide
;
1902 if (!ret
) return FALSE
;
1904 if (prev
&& !hidden
) /* hide the previous one */
1906 /* FIXME: won't work if prev belongs to a different process */
1907 kill_system_timer( prev
, SYSTEM_TIMER_CARET
);
1908 if (old_state
) display_caret( prev
, &r
);
1911 if (caret
.bitmap
) NtGdiDeleteObjectApp( caret
.bitmap
);
1912 caret
.bitmap
= caret_bitmap
;
1913 caret
.timeout
= get_caret_registry_timeout();
1917 /*******************************************************************
1920 BOOL
destroy_caret(void)
1928 SERVER_START_REQ( set_caret_window
)
1933 if ((ret
= !wine_server_call_err( req
)))
1935 prev
= wine_server_ptr_handle( reply
->previous
);
1936 r
.left
= reply
->old_rect
.left
;
1937 r
.top
= reply
->old_rect
.top
;
1938 r
.right
= reply
->old_rect
.right
;
1939 r
.bottom
= reply
->old_rect
.bottom
;
1940 old_state
= reply
->old_state
;
1941 hidden
= reply
->old_hide
;
1946 if (ret
&& prev
&& !hidden
)
1948 /* FIXME: won't work if prev belongs to a different process */
1949 kill_system_timer( prev
, SYSTEM_TIMER_CARET
);
1950 if (old_state
) display_caret( prev
, &r
);
1952 if (caret
.bitmap
) NtGdiDeleteObjectApp( caret
.bitmap
);
1957 /*****************************************************************
1958 * NtUserGetCaretBlinkTime (win32u.@)
1960 UINT WINAPI
NtUserGetCaretBlinkTime(void)
1962 return caret
.timeout
;
1965 /*******************************************************************
1966 * set_caret_blink_time
1968 BOOL
set_caret_blink_time( unsigned int time
)
1970 TRACE( "time %u\n", time
);
1972 caret
.timeout
= time
;
1973 /* FIXME: update the timer */
1977 /*****************************************************************
1978 * NtUserGetCaretPos (win32u.@)
1980 BOOL WINAPI
NtUserGetCaretPos( POINT
*pt
)
1984 SERVER_START_REQ( set_caret_info
)
1986 req
->flags
= 0; /* don't set anything */
1992 if ((ret
= !wine_server_call_err( req
)))
1994 pt
->x
= reply
->old_rect
.left
;
1995 pt
->y
= reply
->old_rect
.top
;
2002 /*******************************************************************
2005 BOOL
set_caret_pos( int x
, int y
)
2013 TRACE( "(%d, %d)\n", x
, y
);
2015 SERVER_START_REQ( set_caret_info
)
2017 req
->flags
= SET_CARET_POS
|SET_CARET_STATE
;
2022 req
->state
= CARET_STATE_ON_IF_MOVED
;
2023 if ((ret
= !wine_server_call_err( req
)))
2025 hwnd
= wine_server_ptr_handle( reply
->full_handle
);
2026 r
.left
= reply
->old_rect
.left
;
2027 r
.top
= reply
->old_rect
.top
;
2028 r
.right
= reply
->old_rect
.right
;
2029 r
.bottom
= reply
->old_rect
.bottom
;
2030 old_state
= reply
->old_state
;
2031 hidden
= reply
->old_hide
;
2035 if (ret
&& !hidden
&& (x
!= r
.left
|| y
!= r
.top
))
2037 if (old_state
) display_caret( hwnd
, &r
);
2038 r
.right
+= x
- r
.left
;
2039 r
.bottom
+= y
- r
.top
;
2042 display_caret( hwnd
, &r
);
2043 NtUserSetSystemTimer( hwnd
, SYSTEM_TIMER_CARET
, caret
.timeout
);
2048 /*****************************************************************
2049 * NtUserShowCaret (win32u.@)
2051 BOOL WINAPI
NtUserShowCaret( HWND hwnd
)
2057 SERVER_START_REQ( set_caret_info
)
2059 req
->flags
= SET_CARET_HIDE
| SET_CARET_STATE
;
2060 req
->handle
= wine_server_user_handle( hwnd
);
2064 req
->state
= CARET_STATE_ON
;
2065 if ((ret
= !wine_server_call_err( req
)))
2067 hwnd
= wine_server_ptr_handle( reply
->full_handle
);
2068 r
.left
= reply
->old_rect
.left
;
2069 r
.top
= reply
->old_rect
.top
;
2070 r
.right
= reply
->old_rect
.right
;
2071 r
.bottom
= reply
->old_rect
.bottom
;
2072 hidden
= reply
->old_hide
;
2077 if (ret
&& hidden
== 1) /* hidden was 1 so it's now 0 */
2079 display_caret( hwnd
, &r
);
2080 NtUserSetSystemTimer( hwnd
, SYSTEM_TIMER_CARET
, caret
.timeout
);
2085 /*****************************************************************
2086 * NtUserHideCaret (win32u.@)
2088 BOOL WINAPI
NtUserHideCaret( HWND hwnd
)
2095 SERVER_START_REQ( set_caret_info
)
2097 req
->flags
= SET_CARET_HIDE
| SET_CARET_STATE
;
2098 req
->handle
= wine_server_user_handle( hwnd
);
2102 req
->state
= CARET_STATE_OFF
;
2103 if ((ret
= !wine_server_call_err( req
)))
2105 hwnd
= wine_server_ptr_handle( reply
->full_handle
);
2106 r
.left
= reply
->old_rect
.left
;
2107 r
.top
= reply
->old_rect
.top
;
2108 r
.right
= reply
->old_rect
.right
;
2109 r
.bottom
= reply
->old_rect
.bottom
;
2110 old_state
= reply
->old_state
;
2111 hidden
= reply
->old_hide
;
2118 if (old_state
) display_caret( hwnd
, &r
);
2119 kill_system_timer( hwnd
, SYSTEM_TIMER_CARET
);
2124 void toggle_caret( HWND hwnd
)
2130 SERVER_START_REQ( set_caret_info
)
2132 req
->flags
= SET_CARET_STATE
;
2133 req
->handle
= wine_server_user_handle( hwnd
);
2137 req
->state
= CARET_STATE_TOGGLE
;
2138 if ((ret
= !wine_server_call( req
)))
2140 hwnd
= wine_server_ptr_handle( reply
->full_handle
);
2141 r
.left
= reply
->old_rect
.left
;
2142 r
.top
= reply
->old_rect
.top
;
2143 r
.right
= reply
->old_rect
.right
;
2144 r
.bottom
= reply
->old_rect
.bottom
;
2145 hidden
= reply
->old_hide
;
2150 if (ret
&& !hidden
) display_caret( hwnd
, &r
);