2 * USER Input processing
4 * Copyright 1993 Bob Amstadt
5 * Copyright 1996 Albrecht Kleine
6 * Copyright 1997 David Faure
7 * Copyright 1998 Morten Welinder
8 * Copyright 1998 Ulrich Weigand
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
32 #define NONAMELESSUNION
35 #define WIN32_NO_STATUS
44 #include "user_private.h"
46 #include "wine/server.h"
47 #include "wine/debug.h"
49 WINE_DEFAULT_DEBUG_CHANNEL(win
);
50 WINE_DECLARE_DEBUG_CHANNEL(keyboard
);
52 INT global_key_state_counter
= 0;
54 /***********************************************************************
57 static WORD
get_key_state(void)
61 if (GetSystemMetrics( SM_SWAPBUTTON
))
63 if (GetAsyncKeyState(VK_RBUTTON
) & 0x80) ret
|= MK_LBUTTON
;
64 if (GetAsyncKeyState(VK_LBUTTON
) & 0x80) ret
|= MK_RBUTTON
;
68 if (GetAsyncKeyState(VK_LBUTTON
) & 0x80) ret
|= MK_LBUTTON
;
69 if (GetAsyncKeyState(VK_RBUTTON
) & 0x80) ret
|= MK_RBUTTON
;
71 if (GetAsyncKeyState(VK_MBUTTON
) & 0x80) ret
|= MK_MBUTTON
;
72 if (GetAsyncKeyState(VK_SHIFT
) & 0x80) ret
|= MK_SHIFT
;
73 if (GetAsyncKeyState(VK_CONTROL
) & 0x80) ret
|= MK_CONTROL
;
74 if (GetAsyncKeyState(VK_XBUTTON1
) & 0x80) ret
|= MK_XBUTTON1
;
75 if (GetAsyncKeyState(VK_XBUTTON2
) & 0x80) ret
|= MK_XBUTTON2
;
80 /***********************************************************************
81 * get_locale_kbd_layout
83 static HKL
get_locale_kbd_layout(void)
90 * layout = main_key_tab[kbd_layout].lcid;
92 * Winword uses return value of GetKeyboardLayout as a codepage
93 * to translate ANSI keyboard messages to unicode. But we have
94 * a problem with it: for instance Polish keyboard layout is
95 * identical to the US one, and therefore instead of the Polish
96 * locale id we return the US one.
99 layout
= GetUserDefaultLCID();
102 * Microsoft Office expects this value to be something specific
103 * for Japanese and Korean Windows with an IME the value is 0xe001
104 * We should probably check to see if an IME exists and if so then
105 * set this word properly.
107 langid
= PRIMARYLANGID( LANGIDFROMLCID( layout
) );
108 if (langid
== LANG_CHINESE
|| langid
== LANG_JAPANESE
|| langid
== LANG_KOREAN
)
109 layout
= MAKELONG( layout
, 0xe001 ); /* IME */
111 layout
= MAKELONG( layout
, layout
);
117 /**********************************************************************
120 void keyboard_init(void)
122 WCHAR layout
[KL_NAMELENGTH
];
125 if (RegCreateKeyExW( HKEY_CURRENT_USER
, L
"Keyboard Layout\\Preload", 0, NULL
, 0,
126 KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
))
129 if (GetKeyboardLayoutNameW( layout
))
130 RegSetValueExW( hkey
, L
"1", 0, REG_SZ
, (const BYTE
*)layout
, sizeof(layout
) );
136 /**********************************************************************
139 BOOL
set_capture_window( HWND hwnd
, UINT gui_flags
, HWND
*prev_ret
)
145 if (gui_flags
& GUI_INMENUMODE
) flags
|= CAPTURE_MENU
;
146 if (gui_flags
& GUI_INMOVESIZE
) flags
|= CAPTURE_MOVESIZE
;
148 SERVER_START_REQ( set_capture_window
)
150 req
->handle
= wine_server_user_handle( hwnd
);
152 if ((ret
= !wine_server_call_err( req
)))
154 previous
= wine_server_ptr_handle( reply
->previous
);
155 hwnd
= wine_server_ptr_handle( reply
->full_handle
);
162 USER_Driver
->pSetCapture( hwnd
, gui_flags
);
165 SendMessageW( previous
, WM_CAPTURECHANGED
, 0, (LPARAM
)hwnd
);
167 if (prev_ret
) *prev_ret
= previous
;
173 /***********************************************************************
174 * __wine_send_input (USER32.@)
176 * Internal SendInput function to allow the graphics driver to inject real events.
178 BOOL CDECL
__wine_send_input( HWND hwnd
, const INPUT
*input
, const RAWINPUT
*rawinput
)
180 NTSTATUS status
= send_hardware_message( hwnd
, input
, rawinput
, 0 );
181 if (status
) SetLastError( RtlNtStatusToDosError(status
) );
186 /***********************************************************************
187 * update_mouse_coords
189 * Helper for SendInput.
191 static void update_mouse_coords( INPUT
*input
)
193 if (!(input
->u
.mi
.dwFlags
& MOUSEEVENTF_MOVE
)) return;
195 if (input
->u
.mi
.dwFlags
& MOUSEEVENTF_ABSOLUTE
)
197 DPI_AWARENESS_CONTEXT context
= SetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE
);
200 if (input
->u
.mi
.dwFlags
& MOUSEEVENTF_VIRTUALDESK
)
201 rc
= get_virtual_screen_rect();
203 rc
= get_primary_monitor_rect();
205 input
->u
.mi
.dx
= rc
.left
+ ((input
->u
.mi
.dx
* (rc
.right
- rc
.left
)) >> 16);
206 input
->u
.mi
.dy
= rc
.top
+ ((input
->u
.mi
.dy
* (rc
.bottom
- rc
.top
)) >> 16);
207 SetThreadDpiAwarenessContext( context
);
213 /* dx and dy can be negative numbers for relative movements */
214 SystemParametersInfoW(SPI_GETMOUSE
, 0, accel
, 0);
216 if (!accel
[2]) return;
218 if (abs(input
->u
.mi
.dx
) > accel
[0])
221 if ((abs(input
->u
.mi
.dx
) > accel
[1]) && (accel
[2] == 2)) input
->u
.mi
.dx
*= 2;
223 if (abs(input
->u
.mi
.dy
) > accel
[0])
226 if ((abs(input
->u
.mi
.dy
) > accel
[1]) && (accel
[2] == 2)) input
->u
.mi
.dy
*= 2;
231 /***********************************************************************
232 * SendInput (USER32.@)
234 UINT WINAPI
SendInput( UINT count
, LPINPUT inputs
, int size
)
237 NTSTATUS status
= STATUS_SUCCESS
;
239 if (size
!= sizeof(INPUT
))
241 SetLastError( ERROR_INVALID_PARAMETER
);
247 SetLastError( ERROR_INVALID_PARAMETER
);
253 SetLastError( ERROR_NOACCESS
);
257 for (i
= 0; i
< count
; i
++)
259 INPUT input
= inputs
[i
];
263 /* we need to update the coordinates to what the server expects */
264 update_mouse_coords( &input
);
267 status
= send_hardware_message( 0, &input
, NULL
, SEND_HWMSG_INJECTED
);
270 SetLastError( ERROR_CALL_NOT_IMPLEMENTED
);
276 SetLastError( RtlNtStatusToDosError(status
) );
285 /***********************************************************************
286 * keybd_event (USER32.@)
288 void WINAPI
keybd_event( BYTE bVk
, BYTE bScan
,
289 DWORD dwFlags
, ULONG_PTR dwExtraInfo
)
293 input
.type
= INPUT_KEYBOARD
;
294 input
.u
.ki
.wVk
= bVk
;
295 input
.u
.ki
.wScan
= bScan
;
296 input
.u
.ki
.dwFlags
= dwFlags
;
298 input
.u
.ki
.dwExtraInfo
= dwExtraInfo
;
299 SendInput( 1, &input
, sizeof(input
) );
303 /***********************************************************************
304 * mouse_event (USER32.@)
306 void WINAPI
mouse_event( DWORD dwFlags
, DWORD dx
, DWORD dy
,
307 DWORD dwData
, ULONG_PTR dwExtraInfo
)
311 input
.type
= INPUT_MOUSE
;
314 input
.u
.mi
.mouseData
= dwData
;
315 input
.u
.mi
.dwFlags
= dwFlags
;
317 input
.u
.mi
.dwExtraInfo
= dwExtraInfo
;
318 SendInput( 1, &input
, sizeof(input
) );
322 /***********************************************************************
323 * GetCursorPos (USER32.@)
325 BOOL WINAPI DECLSPEC_HOTPATCH
GetCursorPos( POINT
*pt
)
331 if (!pt
) return FALSE
;
333 SERVER_START_REQ( set_cursor
)
335 if ((ret
= !wine_server_call( req
)))
337 pt
->x
= reply
->new_x
;
338 pt
->y
= reply
->new_y
;
339 last_change
= reply
->last_change
;
344 /* query new position from graphics driver if we haven't updated recently */
345 if (ret
&& GetTickCount() - last_change
> 100) ret
= USER_Driver
->pGetCursorPos( pt
);
346 if (ret
&& (dpi
= get_thread_dpi()))
348 DPI_AWARENESS_CONTEXT context
;
349 context
= SetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE
);
350 *pt
= map_dpi_point( *pt
, get_monitor_dpi( MonitorFromPoint( *pt
, MONITOR_DEFAULTTOPRIMARY
)), dpi
);
351 SetThreadDpiAwarenessContext( context
);
357 /***********************************************************************
358 * GetCursorInfo (USER32.@)
360 BOOL WINAPI
GetCursorInfo( PCURSORINFO pci
)
364 if (!pci
) return FALSE
;
366 SERVER_START_REQ( get_thread_input
)
369 if ((ret
= !wine_server_call( req
)))
371 pci
->hCursor
= wine_server_ptr_handle( reply
->cursor
);
372 pci
->flags
= (reply
->show_count
>= 0) ? CURSOR_SHOWING
: 0;
376 GetCursorPos(&pci
->ptScreenPos
);
381 /***********************************************************************
382 * SetCursorPos (USER32.@)
384 BOOL WINAPI DECLSPEC_HOTPATCH
SetCursorPos( INT x
, INT y
)
388 INT prev_x
, prev_y
, new_x
, new_y
;
391 if ((dpi
= get_thread_dpi()))
392 pt
= map_dpi_point( pt
, dpi
, get_monitor_dpi( MonitorFromPoint( pt
, MONITOR_DEFAULTTOPRIMARY
)));
394 SERVER_START_REQ( set_cursor
)
396 req
->flags
= SET_CURSOR_POS
;
399 if ((ret
= !wine_server_call( req
)))
401 prev_x
= reply
->prev_x
;
402 prev_y
= reply
->prev_y
;
403 new_x
= reply
->new_x
;
404 new_y
= reply
->new_y
;
408 if (ret
&& (prev_x
!= new_x
|| prev_y
!= new_y
)) USER_Driver
->pSetCursorPos( new_x
, new_y
);
412 /**********************************************************************
413 * SetCapture (USER32.@)
415 HWND WINAPI DECLSPEC_HOTPATCH
SetCapture( HWND hwnd
)
419 set_capture_window( hwnd
, 0, &previous
);
424 /**********************************************************************
425 * ReleaseCapture (USER32.@)
427 BOOL WINAPI DECLSPEC_HOTPATCH
ReleaseCapture(void)
429 BOOL ret
= set_capture_window( 0, 0, NULL
);
431 /* Somebody may have missed some mouse movements */
432 if (ret
) mouse_event( MOUSEEVENTF_MOVE
, 0, 0, 0, 0 );
438 /**********************************************************************
439 * GetCapture (USER32.@)
441 HWND WINAPI
GetCapture(void)
445 SERVER_START_REQ( get_thread_input
)
447 req
->tid
= GetCurrentThreadId();
448 if (!wine_server_call_err( req
)) ret
= wine_server_ptr_handle( reply
->capture
);
455 static void check_for_events( UINT flags
)
457 if (USER_Driver
->pMsgWaitForMultipleObjectsEx( 0, NULL
, 0, flags
, 0 ) == WAIT_TIMEOUT
)
458 flush_window_surfaces( TRUE
);
461 /**********************************************************************
462 * GetAsyncKeyState (USER32.@)
464 * Determine if a key is or was pressed. retval has high-order
465 * bit set to 1 if currently pressed, low-order bit set to 1 if key has
468 SHORT WINAPI DECLSPEC_HOTPATCH
GetAsyncKeyState( INT key
)
470 struct user_key_state_info
*key_state_info
= get_user_thread_info()->key_state
;
471 INT counter
= global_key_state_counter
;
475 if (key
< 0 || key
>= 256) return 0;
477 check_for_events( QS_INPUT
);
479 if (key_state_info
&& !(key_state_info
->state
[key
] & 0xc0) &&
480 key_state_info
->counter
== counter
&& GetTickCount() - key_state_info
->time
< 50)
482 /* use cached value */
485 else if (!key_state_info
)
487 key_state_info
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*key_state_info
) );
488 get_user_thread_info()->key_state
= key_state_info
;
492 SERVER_START_REQ( get_key_state
)
498 prev_key_state
= key_state_info
->state
[key
];
499 wine_server_set_reply( req
, key_state_info
->state
, sizeof(key_state_info
->state
) );
501 if (!wine_server_call( req
))
503 if (reply
->state
& 0x40) ret
|= 0x0001;
504 if (reply
->state
& 0x80) ret
|= 0x8000;
507 /* force refreshing the key state cache - some multithreaded programs
508 * (like Adobe Photoshop CS5) expect that changes to the async key state
509 * are also immediately available in other threads. */
510 if (prev_key_state
!= key_state_info
->state
[key
])
511 counter
= InterlockedIncrement( &global_key_state_counter
);
513 key_state_info
->time
= GetTickCount();
514 key_state_info
->counter
= counter
;
524 /***********************************************************************
525 * GetQueueStatus (USER32.@)
527 DWORD WINAPI
GetQueueStatus( UINT flags
)
531 if (flags
& ~(QS_ALLINPUT
| QS_ALLPOSTMESSAGE
| QS_SMRESULT
))
533 SetLastError( ERROR_INVALID_FLAGS
);
537 check_for_events( flags
);
539 SERVER_START_REQ( get_queue_status
)
541 req
->clear_bits
= flags
;
542 wine_server_call( req
);
543 ret
= MAKELONG( reply
->changed_bits
& flags
, reply
->wake_bits
& flags
);
550 /***********************************************************************
551 * GetInputState (USER32.@)
553 BOOL WINAPI
GetInputState(void)
557 check_for_events( QS_INPUT
);
559 SERVER_START_REQ( get_queue_status
)
562 wine_server_call( req
);
563 ret
= reply
->wake_bits
& (QS_KEY
| QS_MOUSEBUTTON
);
570 /******************************************************************
571 * GetLastInputInfo (USER32.@)
573 BOOL WINAPI
GetLastInputInfo(PLASTINPUTINFO plii
)
579 if (plii
->cbSize
!= sizeof (*plii
) )
581 SetLastError(ERROR_INVALID_PARAMETER
);
585 SERVER_START_REQ( get_last_input_time
)
587 ret
= !wine_server_call_err( req
);
589 plii
->dwTime
= reply
->time
;
596 /**********************************************************************
597 * AttachThreadInput (USER32.@)
599 * Attaches the input processing mechanism of one thread to that of
602 BOOL WINAPI
AttachThreadInput( DWORD from
, DWORD to
, BOOL attach
)
606 SERVER_START_REQ( attach_thread_input
)
608 req
->tid_from
= from
;
610 req
->attach
= attach
;
611 ret
= !wine_server_call_err( req
);
618 /**********************************************************************
619 * GetKeyState (USER32.@)
621 * An application calls the GetKeyState function in response to a
622 * keyboard-input message. This function retrieves the state of the key
623 * at the time the input message was generated.
625 SHORT WINAPI DECLSPEC_HOTPATCH
GetKeyState(INT vkey
)
629 SERVER_START_REQ( get_key_state
)
632 if (!wine_server_call( req
)) retval
= (signed char)(reply
->state
& 0x81);
635 TRACE("key (0x%x) -> %x\n", vkey
, retval
);
640 /**********************************************************************
641 * GetKeyboardState (USER32.@)
643 BOOL WINAPI DECLSPEC_HOTPATCH
GetKeyboardState( LPBYTE state
)
648 TRACE("(%p)\n", state
);
650 memset( state
, 0, 256 );
651 SERVER_START_REQ( get_key_state
)
654 wine_server_set_reply( req
, state
, 256 );
655 ret
= !wine_server_call_err( req
);
656 for (i
= 0; i
< 256; i
++) state
[i
] &= 0x81;
663 /**********************************************************************
664 * SetKeyboardState (USER32.@)
666 BOOL WINAPI
SetKeyboardState( LPBYTE state
)
670 SERVER_START_REQ( set_key_state
)
672 wine_server_add_data( req
, state
, 256 );
673 ret
= !wine_server_call_err( req
);
680 /**********************************************************************
681 * VkKeyScanA (USER32.@)
683 * VkKeyScan translates an ANSI character to a virtual-key and shift code
684 * for the current keyboard.
685 * high-order byte yields :
689 * 3-5 Shift-key combinations that are not used for characters
692 * I.e. : Shift = 1, Ctrl = 2, Alt = 4.
693 * FIXME : works ok except for dead chars :
694 * VkKeyScan '^'(0x5e, 94) ... got keycode 00 ... returning 00
695 * VkKeyScan '`'(0x60, 96) ... got keycode 00 ... returning 00
697 SHORT WINAPI
VkKeyScanA(CHAR cChar
)
701 if (IsDBCSLeadByte(cChar
)) return -1;
703 MultiByteToWideChar(CP_ACP
, 0, &cChar
, 1, &wChar
, 1);
704 return VkKeyScanW(wChar
);
707 /******************************************************************************
708 * VkKeyScanW (USER32.@)
710 SHORT WINAPI
VkKeyScanW(WCHAR cChar
)
712 return VkKeyScanExW(cChar
, GetKeyboardLayout(0));
715 /**********************************************************************
716 * VkKeyScanExA (USER32.@)
718 WORD WINAPI
VkKeyScanExA(CHAR cChar
, HKL dwhkl
)
722 if (IsDBCSLeadByte(cChar
)) return -1;
724 MultiByteToWideChar(CP_ACP
, 0, &cChar
, 1, &wChar
, 1);
725 return VkKeyScanExW(wChar
, dwhkl
);
728 /******************************************************************************
729 * VkKeyScanExW (USER32.@)
731 WORD WINAPI
VkKeyScanExW( WCHAR chr
, HKL layout
)
733 WORD shift
= 0x100, ctrl
= 0x200;
736 TRACE_(keyboard
)( "chr %s, layout %p\n", debugstr_wn(&chr
, 1), layout
);
738 if ((ret
= USER_Driver
->pVkKeyScanEx( chr
, layout
)) != -256) return ret
;
740 /* FIXME: English keyboard layout specific */
742 if (chr
== VK_CANCEL
|| chr
== VK_BACK
|| chr
== VK_TAB
|| chr
== VK_RETURN
||
743 chr
== VK_ESCAPE
|| chr
== VK_SPACE
) ret
= chr
;
744 else if (chr
>= '0' && chr
<= '9') ret
= chr
;
745 else if (chr
== ')') ret
= shift
+ '0';
746 else if (chr
== '!') ret
= shift
+ '1';
747 else if (chr
== '@') ret
= shift
+ '2';
748 else if (chr
== '#') ret
= shift
+ '3';
749 else if (chr
== '$') ret
= shift
+ '4';
750 else if (chr
== '%') ret
= shift
+ '5';
751 else if (chr
== '^') ret
= shift
+ '6';
752 else if (chr
== '&') ret
= shift
+ '7';
753 else if (chr
== '*') ret
= shift
+ '8';
754 else if (chr
== '(') ret
= shift
+ '9';
755 else if (chr
>= 'a' && chr
<= 'z') ret
= chr
- 'a' + 'A';
756 else if (chr
>= 'A' && chr
<= 'Z') ret
= shift
+ chr
;
757 else if (chr
== ';') ret
= VK_OEM_1
;
758 else if (chr
== '=') ret
= VK_OEM_PLUS
;
759 else if (chr
== ',') ret
= VK_OEM_COMMA
;
760 else if (chr
== '-') ret
= VK_OEM_MINUS
;
761 else if (chr
== '.') ret
= VK_OEM_PERIOD
;
762 else if (chr
== '/') ret
= VK_OEM_2
;
763 else if (chr
== '`') ret
= VK_OEM_3
;
764 else if (chr
== '[') ret
= VK_OEM_4
;
765 else if (chr
== '\\') ret
= VK_OEM_5
;
766 else if (chr
== ']') ret
= VK_OEM_6
;
767 else if (chr
== '\'') ret
= VK_OEM_7
;
768 else if (chr
== ':') ret
= shift
+ VK_OEM_1
;
769 else if (chr
== '+') ret
= shift
+ VK_OEM_PLUS
;
770 else if (chr
== '<') ret
= shift
+ VK_OEM_COMMA
;
771 else if (chr
== '_') ret
= shift
+ VK_OEM_MINUS
;
772 else if (chr
== '>') ret
= shift
+ VK_OEM_PERIOD
;
773 else if (chr
== '?') ret
= shift
+ VK_OEM_2
;
774 else if (chr
== '~') ret
= shift
+ VK_OEM_3
;
775 else if (chr
== '{') ret
= shift
+ VK_OEM_4
;
776 else if (chr
== '|') ret
= shift
+ VK_OEM_5
;
777 else if (chr
== '}') ret
= shift
+ VK_OEM_6
;
778 else if (chr
== '\"') ret
= shift
+ VK_OEM_7
;
779 else if (chr
== 0x7f) ret
= ctrl
+ VK_BACK
;
780 else if (chr
== '\n') ret
= ctrl
+ VK_RETURN
;
781 else if (chr
== 0xf000) ret
= ctrl
+ '2';
782 else if (chr
== 0x0000) ret
= ctrl
+ shift
+ '2';
783 else if (chr
>= 0x0001 && chr
<= 0x001a) ret
= ctrl
+ 'A' + chr
- 1;
784 else if (chr
>= 0x001c && chr
<= 0x001d) ret
= ctrl
+ VK_OEM_3
+ chr
;
785 else if (chr
== 0x001e) ret
= ctrl
+ shift
+ '6';
786 else if (chr
== 0x001f) ret
= ctrl
+ shift
+ VK_OEM_MINUS
;
789 TRACE_(keyboard
)( "ret %04x\n", ret
);
793 /**********************************************************************
794 * OemKeyScan (USER32.@)
796 DWORD WINAPI
OemKeyScan( WORD oem
)
800 char oem_char
= LOBYTE( oem
);
802 if (!OemToCharBuffW( &oem_char
, &wchr
, 1 ))
805 vkey
= VkKeyScanW( wchr
);
806 scan
= MapVirtualKeyW( LOBYTE( vkey
), MAPVK_VK_TO_VSC
);
807 if (!scan
) return -1;
814 /******************************************************************************
815 * GetKeyboardType (USER32.@)
817 INT WINAPI
GetKeyboardType(INT nTypeFlag
)
819 TRACE_(keyboard
)("(%d)\n", nTypeFlag
);
820 if (LOWORD(GetKeyboardLayout(0)) == MAKELANGID(LANG_JAPANESE
, SUBLANG_JAPANESE_JAPAN
))
822 /* scan code for `_', the key left of r-shift, in Japanese 106 keyboard */
823 const UINT JP106_VSC_USCORE
= 0x73;
827 case 0: /* Keyboard type */
828 return 7; /* Japanese keyboard */
829 case 1: /* Keyboard Subtype */
830 /* Test keyboard mappings to detect Japanese keyboard */
831 if (MapVirtualKeyW(VK_OEM_102
, MAPVK_VK_TO_VSC
) == JP106_VSC_USCORE
832 && MapVirtualKeyW(JP106_VSC_USCORE
, MAPVK_VSC_TO_VK
) == VK_OEM_102
)
833 return 2; /* Japanese 106 */
835 return 0; /* AT-101 */
836 case 2: /* Number of F-keys */
837 return 12; /* It has 12 F-keys */
844 case 0: /* Keyboard type */
845 return 4; /* AT-101 */
846 case 1: /* Keyboard Subtype */
847 return 0; /* There are no defined subtypes */
848 case 2: /* Number of F-keys */
849 return 12; /* We're doing an 101 for now, so return 12 F-keys */
852 WARN_(keyboard
)("Unknown type\n");
853 return 0; /* The book says 0 here, so 0 */
856 /******************************************************************************
857 * MapVirtualKeyA (USER32.@)
859 UINT WINAPI
MapVirtualKeyA(UINT code
, UINT maptype
)
861 return MapVirtualKeyExA( code
, maptype
, GetKeyboardLayout(0) );
864 /******************************************************************************
865 * MapVirtualKeyW (USER32.@)
867 UINT WINAPI
MapVirtualKeyW(UINT code
, UINT maptype
)
869 return MapVirtualKeyExW(code
, maptype
, GetKeyboardLayout(0));
872 /******************************************************************************
873 * MapVirtualKeyExA (USER32.@)
875 UINT WINAPI
MapVirtualKeyExA(UINT code
, UINT maptype
, HKL hkl
)
879 ret
= MapVirtualKeyExW( code
, maptype
, hkl
);
880 if (maptype
== MAPVK_VK_TO_CHAR
)
885 WideCharToMultiByte( CP_ACP
, 0, &wch
, 1, (LPSTR
)&ch
, 1, NULL
, NULL
);
892 /* English keyboard layout (0x0409) */
893 static const UINT kbd_en_vsc2vk
[] =
895 0x00, 0x1b, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0xbd, 0xbb, 0x08, 0x09,
896 0x51, 0x57, 0x45, 0x52, 0x54, 0x59, 0x55, 0x49, 0x4f, 0x50, 0xdb, 0xdd, 0x0d, 0xa2, 0x41, 0x53,
897 0x44, 0x46, 0x47, 0x48, 0x4a, 0x4b, 0x4c, 0xba, 0xde, 0xc0, 0xa0, 0xdc, 0x5a, 0x58, 0x43, 0x56,
898 0x42, 0x4e, 0x4d, 0xbc, 0xbe, 0xbf, 0xa1, 0x6a, 0xa4, 0x20, 0x14, 0x70, 0x71, 0x72, 0x73, 0x74,
899 0x75, 0x76, 0x77, 0x78, 0x79, 0x90, 0x91, 0x24, 0x26, 0x21, 0x6d, 0x25, 0x0c, 0x27, 0x6b, 0x23,
900 0x28, 0x22, 0x2d, 0x2e, 0x2c, 0x00, 0xe2, 0x7a, 0x7b, 0x0c, 0xee, 0xf1, 0xea, 0xf9, 0xf5, 0xf3,
901 0x00, 0x00, 0xfb, 0x2f, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0xed,
902 0x00, 0xe9, 0x00, 0xc1, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, 0x00, 0xeb, 0x09, 0x00, 0xc2, 0x00,
903 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
904 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
905 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
906 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
907 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
908 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
909 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
910 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
912 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
913 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x0d, 0xa3, 0x00, 0x00,
914 0xad, 0xb7, 0xb3, 0x00, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xae, 0x00,
915 0xaf, 0x00, 0xac, 0x00, 0x00, 0x6f, 0x00, 0x2c, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
916 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x24, 0x26, 0x21, 0x00, 0x25, 0x00, 0x27, 0x00, 0x23,
917 0x28, 0x22, 0x2d, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5b, 0x5c, 0x5d, 0x00, 0x5f,
918 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xab, 0xa8, 0xa9, 0xa7, 0xa6, 0xb6, 0xb4, 0xb5, 0x00, 0x00,
919 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
920 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
921 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
922 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
923 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
924 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
925 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
926 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
927 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
929 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
930 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00,
931 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
932 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
933 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
934 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
935 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
936 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
937 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
938 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
939 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
940 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
941 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
942 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
943 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
944 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
947 static const UINT kbd_en_vk2char
[] =
949 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x08, 0x09, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00,
950 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00,
951 ' ', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
952 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
953 0x00, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
954 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 0x00, 0x00, 0x00, 0x00, 0x00,
955 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '*', '+', 0x00, '-', '.', '/',
956 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
957 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
958 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
959 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
960 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ';', '=', ',', '-', '.', '/',
961 '`', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
962 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, '[', '\\', ']', '\'', 0x00,
963 0x00, 0x00, '\\', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
964 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
967 static const WCHAR
*kbd_en_vscname
[] =
969 0, L
"Esc", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, L
"Backspace", L
"Tab",
970 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, L
"Enter", L
"Ctrl", 0, 0,
971 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, L
"Shift", 0, 0, 0, 0, 0,
972 0, 0, 0, 0, 0, 0, L
"Right Shift", L
"Num *", L
"Alt", L
"Space", L
"Caps Lock", L
"F1", L
"F2", L
"F3", L
"F4", L
"F5",
973 L
"F6", L
"F7", L
"F8", L
"F9", L
"F10", L
"Pause", L
"Scroll Lock", L
"Num 7", L
"Num 8", L
"Num 9", L
"Num -", L
"Num 4", L
"Num 5", L
"Num 6", L
"Num +", L
"Num 1",
974 L
"Num 2", L
"Num 3", L
"Num 0", L
"Num Del", L
"Sys Req", 0, 0, L
"F11", L
"F12", 0, 0, 0, 0, 0, 0, 0,
975 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
976 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, L
"F13", L
"F14", L
"F15", L
"F16",
977 L
"F17", L
"F18", L
"F19", L
"F20", L
"F21", L
"F22", L
"F23", L
"F24", 0, 0, 0, 0, 0, 0, 0, 0,
978 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
979 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
980 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
981 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
982 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
983 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
984 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
986 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
987 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, L
"Num Enter", L
"Right Ctrl", 0, 0,
988 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
989 0, 0, 0, 0, 0, L
"Num /", 0, L
"Prnt Scrn", L
"Right Alt", 0, 0, 0, 0, 0, 0, 0,
990 0, 0, 0, 0, 0, L
"Num Lock", L
"Break", L
"Home", L
"Up", L
"Page Up", 0, L
"Left", 0, L
"Right", 0, L
"End",
991 L
"Down", L
"Page Down", L
"Insert", L
"Delete", L
"<00>", 0, L
"Help", 0, 0, 0, 0, L
"Left Windows", L
"Right Windows", L
"Application", 0, 0,
992 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
993 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
994 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
995 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
996 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
997 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
998 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
999 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1000 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1001 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1005 /******************************************************************************
1006 * MapVirtualKeyExW (USER32.@)
1008 UINT WINAPI
MapVirtualKeyExW( UINT code
, UINT type
, HKL layout
)
1010 const UINT
*vsc2vk
, *vk2char
;
1011 UINT vsc2vk_size
, vk2char_size
;
1014 TRACE_(keyboard
)( "code %u, type %u, layout %p.\n", code
, type
, layout
);
1016 if ((ret
= USER_Driver
->pMapVirtualKeyEx( code
, type
, layout
)) != -1) return ret
;
1018 /* FIXME: English keyboard layout specific */
1020 vsc2vk
= kbd_en_vsc2vk
;
1021 vsc2vk_size
= ARRAYSIZE(kbd_en_vsc2vk
);
1022 vk2char
= kbd_en_vk2char
;
1023 vk2char_size
= ARRAYSIZE(kbd_en_vk2char
);
1027 case MAPVK_VK_TO_VSC_EX
:
1028 case MAPVK_VK_TO_VSC
:
1031 case VK_SHIFT
: code
= VK_LSHIFT
; break;
1032 case VK_CONTROL
: code
= VK_LCONTROL
; break;
1033 case VK_MENU
: code
= VK_LMENU
; break;
1034 case VK_NUMPAD0
: code
= VK_INSERT
; break;
1035 case VK_NUMPAD1
: code
= VK_END
; break;
1036 case VK_NUMPAD2
: code
= VK_DOWN
; break;
1037 case VK_NUMPAD3
: code
= VK_NEXT
; break;
1038 case VK_NUMPAD4
: code
= VK_LEFT
; break;
1039 case VK_NUMPAD5
: code
= VK_CLEAR
; break;
1040 case VK_NUMPAD6
: code
= VK_RIGHT
; break;
1041 case VK_NUMPAD7
: code
= VK_HOME
; break;
1042 case VK_NUMPAD8
: code
= VK_UP
; break;
1043 case VK_NUMPAD9
: code
= VK_PRIOR
; break;
1044 case VK_DECIMAL
: code
= VK_DELETE
; break;
1047 for (ret
= 0; ret
< vsc2vk_size
; ++ret
) if (vsc2vk
[ret
] == code
) break;
1048 if (ret
>= vsc2vk_size
) ret
= 0;
1050 if (type
== MAPVK_VK_TO_VSC
)
1052 if (ret
>= 0x200) ret
= 0;
1055 else if (ret
>= 0x100) ret
+= 0xdf00;
1057 case MAPVK_VSC_TO_VK
:
1058 case MAPVK_VSC_TO_VK_EX
:
1059 if (code
& 0xe000) code
-= 0xdf00;
1060 if (code
>= vsc2vk_size
) ret
= 0;
1061 else ret
= vsc2vk
[code
];
1063 if (type
== MAPVK_VSC_TO_VK
)
1067 case VK_LSHIFT
: case VK_RSHIFT
: ret
= VK_SHIFT
; break;
1068 case VK_LCONTROL
: case VK_RCONTROL
: ret
= VK_CONTROL
; break;
1069 case VK_LMENU
: case VK_RMENU
: ret
= VK_MENU
; break;
1073 case MAPVK_VK_TO_CHAR
:
1074 if (code
>= vk2char_size
) ret
= 0;
1075 else ret
= vk2char
[code
];
1078 FIXME_(keyboard
)( "unknown type %d\n", type
);
1082 TRACE_(keyboard
)( "returning 0x%04x\n", ret
);
1086 /****************************************************************************
1087 * GetKBCodePage (USER32.@)
1089 UINT WINAPI
GetKBCodePage(void)
1094 /***********************************************************************
1095 * GetKeyboardLayout (USER32.@)
1097 * - device handle for keyboard layout defaulted to
1098 * the language id. This is the way Windows default works.
1099 * - the thread identifier is also ignored.
1101 HKL WINAPI
GetKeyboardLayout(DWORD thread_id
)
1103 struct user_thread_info
*thread
= get_user_thread_info();
1104 HKL layout
= thread
->kbd_layout
;
1106 if (thread_id
&& thread_id
!= GetCurrentThreadId())
1107 FIXME( "couldn't return keyboard layout for thread %04x\n", thread_id
);
1109 if (!layout
) return get_locale_kbd_layout();
1113 /****************************************************************************
1114 * GetKeyboardLayoutNameA (USER32.@)
1116 BOOL WINAPI
GetKeyboardLayoutNameA(LPSTR pszKLID
)
1118 WCHAR buf
[KL_NAMELENGTH
];
1120 if (GetKeyboardLayoutNameW(buf
))
1121 return WideCharToMultiByte( CP_ACP
, 0, buf
, -1, pszKLID
, KL_NAMELENGTH
, NULL
, NULL
) != 0;
1125 /****************************************************************************
1126 * GetKeyboardLayoutNameW (USER32.@)
1128 BOOL WINAPI
GetKeyboardLayoutNameW( WCHAR
*name
)
1130 struct user_thread_info
*info
= get_user_thread_info();
1131 WCHAR klid
[KL_NAMELENGTH
], value
[5];
1132 DWORD value_size
, tmp
, i
= 0;
1136 TRACE_(keyboard
)( "name %p\n", name
);
1140 SetLastError( ERROR_NOACCESS
);
1144 if (info
->kbd_layout_id
)
1146 swprintf( name
, KL_NAMELENGTH
, L
"%08X", info
->kbd_layout_id
);
1150 layout
= GetKeyboardLayout( 0 );
1151 tmp
= HandleToUlong( layout
);
1152 if (HIWORD( tmp
) == LOWORD( tmp
)) tmp
= LOWORD( tmp
);
1153 swprintf( name
, KL_NAMELENGTH
, L
"%08X", tmp
);
1155 if (!RegOpenKeyW( HKEY_LOCAL_MACHINE
, L
"System\\CurrentControlSet\\Control\\Keyboard Layouts", &hkey
))
1157 while (!RegEnumKeyW( hkey
, i
++, klid
, ARRAY_SIZE(klid
) ))
1159 value_size
= sizeof(value
);
1160 if (!RegGetValueW( hkey
, klid
, L
"Layout Id", RRF_RT_REG_SZ
, NULL
, (void *)&value
, &value_size
))
1161 tmp
= 0xf000 | (wcstoul( value
, NULL
, 16 ) & 0xfff);
1163 tmp
= wcstoul( klid
, NULL
, 16 );
1165 if (HIWORD( layout
) == tmp
)
1167 lstrcpynW( name
, klid
, KL_NAMELENGTH
);
1171 RegCloseKey( hkey
);
1174 info
->kbd_layout_id
= wcstoul( name
, NULL
, 16 );
1176 TRACE_(keyboard
)( "ret %s\n", debugstr_w( name
) );
1180 /****************************************************************************
1181 * GetKeyNameTextA (USER32.@)
1183 INT WINAPI
GetKeyNameTextA(LONG lParam
, LPSTR lpBuffer
, INT nSize
)
1188 if (!nSize
|| !GetKeyNameTextW(lParam
, buf
, 256))
1193 ret
= WideCharToMultiByte(CP_ACP
, 0, buf
, -1, lpBuffer
, nSize
, NULL
, NULL
);
1204 /****************************************************************************
1205 * GetKeyNameTextW (USER32.@)
1207 INT WINAPI
GetKeyNameTextW( LONG lparam
, LPWSTR buffer
, INT size
)
1209 INT code
= ((lparam
>> 16) & 0x1ff), vkey
, len
;
1210 UINT vsc2vk_size
, vscname_size
;
1211 const WCHAR
*const *vscname
;
1215 TRACE_(keyboard
)( "lparam %d, buffer %p, size %d.\n", lparam
, buffer
, size
);
1217 if (!buffer
|| !size
) return 0;
1218 if ((len
= USER_Driver
->pGetKeyNameText( lparam
, buffer
, size
)) >= 0) return len
;
1220 /* FIXME: English keyboard layout specific */
1222 vsc2vk
= kbd_en_vsc2vk
;
1223 vsc2vk_size
= ARRAYSIZE(kbd_en_vsc2vk
);
1224 vscname
= kbd_en_vscname
;
1225 vscname_size
= ARRAYSIZE(kbd_en_vscname
);
1227 if (lparam
& 0x2000000)
1229 switch ((vkey
= vsc2vk
[code
]))
1234 for (code
= 0; code
< vsc2vk_size
; ++code
)
1235 if (vsc2vk
[code
] == (vkey
- 1)) break;
1240 if (code
>= vscname_size
) buffer
[0] = 0;
1241 else if (vscname
[code
]) lstrcpynW( buffer
, vscname
[code
], size
);
1244 vkey
= MapVirtualKeyW( code
& 0xff, MAPVK_VSC_TO_VK
);
1245 tmp
[0] = MapVirtualKeyW( vkey
, MAPVK_VK_TO_CHAR
);
1247 lstrcpynW( buffer
, tmp
, size
);
1249 len
= wcslen( buffer
);
1251 TRACE_(keyboard
)( "ret %d, str %s.\n", len
, debugstr_w(buffer
) );
1255 /****************************************************************************
1256 * ToUnicode (USER32.@)
1258 INT WINAPI
ToUnicode(UINT virtKey
, UINT scanCode
, const BYTE
*lpKeyState
,
1259 LPWSTR lpwStr
, int size
, UINT flags
)
1261 return ToUnicodeEx(virtKey
, scanCode
, lpKeyState
, lpwStr
, size
, flags
, GetKeyboardLayout(0));
1264 /****************************************************************************
1265 * ToUnicodeEx (USER32.@)
1267 INT WINAPI
ToUnicodeEx( UINT virt
, UINT scan
, const BYTE
*state
,
1268 WCHAR
*str
, int size
, UINT flags
, HKL layout
)
1270 BOOL shift
, ctrl
, alt
, numlock
;
1274 TRACE_(keyboard
)( "virt %u, scan %u, state %p, str %p, size %d, flags %x, layout %p.\n",
1275 virt
, scan
, state
, str
, size
, flags
, layout
);
1277 if (!state
) return 0;
1278 if ((len
= USER_Driver
->pToUnicodeEx( virt
, scan
, state
, str
, size
, flags
, layout
)) >= -1) return len
;
1280 alt
= state
[VK_MENU
] & 0x80;
1281 shift
= state
[VK_SHIFT
] & 0x80;
1282 ctrl
= state
[VK_CONTROL
] & 0x80;
1283 numlock
= state
[VK_NUMLOCK
] & 0x01;
1285 /* FIXME: English keyboard layout specific */
1287 if (scan
& 0x8000) buffer
[0] = 0; /* key up */
1288 else if (virt
== VK_ESCAPE
) buffer
[0] = VK_ESCAPE
;
1293 case VK_BACK
: buffer
[0] = '\b'; break;
1294 case VK_OEM_1
: buffer
[0] = shift
? ':' : ';'; break;
1295 case VK_OEM_2
: buffer
[0] = shift
? '?' : '/'; break;
1296 case VK_OEM_3
: buffer
[0] = shift
? '~' : '`'; break;
1297 case VK_OEM_4
: buffer
[0] = shift
? '{' : '['; break;
1298 case VK_OEM_5
: buffer
[0] = shift
? '|' : '\\'; break;
1299 case VK_OEM_6
: buffer
[0] = shift
? '}' : ']'; break;
1300 case VK_OEM_7
: buffer
[0] = shift
? '"' : '\''; break;
1301 case VK_OEM_COMMA
: buffer
[0] = shift
? '<' : ','; break;
1302 case VK_OEM_MINUS
: buffer
[0] = shift
? '_' : '-'; break;
1303 case VK_OEM_PERIOD
: buffer
[0] = shift
? '>' : '.'; break;
1304 case VK_OEM_PLUS
: buffer
[0] = shift
? '+' : '='; break;
1305 case VK_RETURN
: buffer
[0] = '\r'; break;
1306 case VK_SPACE
: buffer
[0] = ' '; break;
1307 case VK_TAB
: buffer
[0] = '\t'; break;
1308 case VK_MULTIPLY
: buffer
[0] = '*'; break;
1309 case VK_ADD
: buffer
[0] = '+'; break;
1310 case VK_SUBTRACT
: buffer
[0] = '-'; break;
1311 case VK_DIVIDE
: buffer
[0] = '/'; break;
1313 if (virt
>= '0' && virt
<= '9')
1314 buffer
[0] = shift
? ")!@#$%^&*("[virt
- '0'] : virt
;
1315 else if (virt
>= 'A' && virt
<= 'Z')
1316 buffer
[0] = shift
|| (state
[VK_CAPITAL
] & 0x01) ? virt
: virt
+ 'a' - 'A';
1317 else if (virt
>= VK_NUMPAD0
&& virt
<= VK_NUMPAD9
&& numlock
&& !shift
)
1318 buffer
[0] = '0' + virt
- VK_NUMPAD0
;
1319 else if (virt
== VK_DECIMAL
&& numlock
&& !shift
)
1326 else if (!alt
) /* Control codes */
1330 case VK_OEM_4
: buffer
[0] = 0x1b; break;
1331 case VK_OEM_5
: buffer
[0] = 0x1c; break;
1332 case VK_OEM_6
: buffer
[0] = 0x1d; break;
1333 case '6': buffer
[0] = shift
? 0x1e : 0; break;
1334 case VK_OEM_MINUS
: buffer
[0] = shift
? 0x1f : 0; break;
1335 case VK_BACK
: buffer
[0] = 0x7f; break;
1336 case VK_RETURN
: buffer
[0] = shift
? 0 : '\n'; break;
1337 case '2': buffer
[0] = shift
? 0xffff : 0xf000; break;
1338 case VK_SPACE
: buffer
[0] = ' '; break;
1340 if (virt
>= 'A' && virt
<= 'Z') buffer
[0] = virt
- 'A' + 1;
1347 len
= wcslen( buffer
);
1348 if (buffer
[0] == 0xffff) buffer
[0] = 0;
1349 lstrcpynW( str
, buffer
, size
);
1351 TRACE_(keyboard
)( "ret %d, str %s.\n", len
, debugstr_w(str
) );
1355 /****************************************************************************
1356 * ToAscii (USER32.@)
1358 INT WINAPI
ToAscii( UINT virtKey
, UINT scanCode
, const BYTE
*lpKeyState
,
1359 LPWORD lpChar
, UINT flags
)
1361 return ToAsciiEx(virtKey
, scanCode
, lpKeyState
, lpChar
, flags
, GetKeyboardLayout(0));
1364 /****************************************************************************
1365 * ToAsciiEx (USER32.@)
1367 INT WINAPI
ToAsciiEx( UINT virtKey
, UINT scanCode
, const BYTE
*lpKeyState
,
1368 LPWORD lpChar
, UINT flags
, HKL dwhkl
)
1373 ret
= ToUnicodeEx(virtKey
, scanCode
, lpKeyState
, uni_chars
, 2, flags
, dwhkl
);
1374 if (ret
< 0) n_ret
= 1; /* FIXME: make ToUnicode return 2 for dead chars */
1376 WideCharToMultiByte(CP_ACP
, 0, uni_chars
, n_ret
, (LPSTR
)lpChar
, 2, NULL
, NULL
);
1380 /**********************************************************************
1381 * ActivateKeyboardLayout (USER32.@)
1383 HKL WINAPI
ActivateKeyboardLayout( HKL layout
, UINT flags
)
1385 struct user_thread_info
*info
= get_user_thread_info();
1388 TRACE_(keyboard
)( "layout %p, flags %x\n", layout
, flags
);
1390 if (flags
) FIXME_(keyboard
)( "flags %x not supported\n", flags
);
1392 if (layout
== (HKL
)HKL_NEXT
|| layout
== (HKL
)HKL_PREV
)
1394 SetLastError( ERROR_CALL_NOT_IMPLEMENTED
);
1395 FIXME_(keyboard
)( "HKL_NEXT and HKL_PREV not supported\n" );
1399 if (!USER_Driver
->pActivateKeyboardLayout( layout
, flags
))
1402 old_layout
= info
->kbd_layout
;
1403 info
->kbd_layout
= layout
;
1404 if (old_layout
!= layout
) info
->kbd_layout_id
= 0;
1406 if (!old_layout
) return get_locale_kbd_layout();
1410 /**********************************************************************
1411 * BlockInput (USER32.@)
1413 BOOL WINAPI
BlockInput(BOOL fBlockIt
)
1415 FIXME_(keyboard
)("(%d): stub\n", fBlockIt
);
1416 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1421 /***********************************************************************
1422 * GetKeyboardLayoutList (USER32.@)
1424 * Return number of values available if either input parm is
1425 * 0, per MS documentation.
1427 UINT WINAPI
GetKeyboardLayoutList( INT size
, HKL
*layouts
)
1429 WCHAR klid
[KL_NAMELENGTH
], value
[5];
1430 DWORD value_size
, count
, tmp
, i
= 0;
1434 TRACE_(keyboard
)( "size %d, layouts %p.\n", size
, layouts
);
1436 if ((count
= USER_Driver
->pGetKeyboardLayoutList( size
, layouts
)) != ~0) return count
;
1438 layout
= get_locale_kbd_layout();
1442 if (size
&& layouts
)
1444 layouts
[count
- 1] = layout
;
1445 if (count
== size
) return count
;
1448 if (!RegOpenKeyW( HKEY_LOCAL_MACHINE
, L
"System\\CurrentControlSet\\Control\\Keyboard Layouts", &hkey
))
1450 while (!RegEnumKeyW( hkey
, i
++, klid
, ARRAY_SIZE(klid
) ))
1452 tmp
= wcstoul( klid
, NULL
, 16 );
1453 value_size
= sizeof(value
);
1454 if (!RegGetValueW( hkey
, klid
, L
"Layout Id", RRF_RT_REG_SZ
, NULL
, (void *)&value
, &value_size
))
1455 tmp
= MAKELONG( LOWORD( tmp
), 0xf000 | (wcstoul( value
, NULL
, 16 ) & 0xfff) );
1457 if (layout
== UlongToHandle( tmp
)) continue;
1460 if (size
&& layouts
)
1462 layouts
[count
- 1] = UlongToHandle( tmp
);
1463 if (count
== size
) break;
1466 RegCloseKey( hkey
);
1473 /***********************************************************************
1474 * RegisterHotKey (USER32.@)
1476 BOOL WINAPI
RegisterHotKey(HWND hwnd
,INT id
,UINT modifiers
,UINT vk
)
1481 TRACE_(keyboard
)("(%p,%d,0x%08x,%X)\n",hwnd
,id
,modifiers
,vk
);
1483 if ((hwnd
== NULL
|| WIN_IsCurrentThread(hwnd
)) &&
1484 !USER_Driver
->pRegisterHotKey(hwnd
, modifiers
, vk
))
1487 SERVER_START_REQ( register_hotkey
)
1489 req
->window
= wine_server_user_handle( hwnd
);
1491 req
->flags
= modifiers
;
1493 if ((ret
= !wine_server_call_err( req
)))
1495 replaced
= reply
->replaced
;
1496 modifiers
= reply
->flags
;
1502 if (ret
&& replaced
)
1503 USER_Driver
->pUnregisterHotKey(hwnd
, modifiers
, vk
);
1508 /***********************************************************************
1509 * UnregisterHotKey (USER32.@)
1511 BOOL WINAPI
UnregisterHotKey(HWND hwnd
,INT id
)
1516 TRACE_(keyboard
)("(%p,%d)\n",hwnd
,id
);
1518 SERVER_START_REQ( unregister_hotkey
)
1520 req
->window
= wine_server_user_handle( hwnd
);
1522 if ((ret
= !wine_server_call_err( req
)))
1524 modifiers
= reply
->flags
;
1531 USER_Driver
->pUnregisterHotKey(hwnd
, modifiers
, vk
);
1536 /***********************************************************************
1537 * LoadKeyboardLayoutW (USER32.@)
1539 HKL WINAPI
LoadKeyboardLayoutW( const WCHAR
*name
, UINT flags
)
1541 WCHAR layout_path
[MAX_PATH
], value
[5];
1542 DWORD value_size
, tmp
;
1546 FIXME_(keyboard
)( "name %s, flags %x, semi-stub!\n", debugstr_w( name
), flags
);
1548 tmp
= wcstoul( name
, NULL
, 16 );
1549 if (HIWORD( tmp
)) layout
= UlongToHandle( tmp
);
1550 else layout
= UlongToHandle( MAKELONG( LOWORD( tmp
), LOWORD( tmp
) ) );
1552 wcscpy( layout_path
, L
"System\\CurrentControlSet\\Control\\Keyboard Layouts\\" );
1553 wcscat( layout_path
, name
);
1555 if (!RegOpenKeyW( HKEY_LOCAL_MACHINE
, layout_path
, &hkey
))
1557 value_size
= sizeof(value
);
1558 if (!RegGetValueW( hkey
, NULL
, L
"Layout Id", RRF_RT_REG_SZ
, NULL
, (void *)&value
, &value_size
))
1559 layout
= UlongToHandle( MAKELONG( LOWORD( tmp
), 0xf000 | (wcstoul( value
, NULL
, 16 ) & 0xfff) ) );
1561 RegCloseKey( hkey
);
1564 if ((flags
& KLF_ACTIVATE
) && ActivateKeyboardLayout( layout
, 0 )) return layout
;
1566 /* FIXME: semi-stub: returning default layout */
1567 return get_locale_kbd_layout();
1570 /***********************************************************************
1571 * LoadKeyboardLayoutA (USER32.@)
1573 HKL WINAPI
LoadKeyboardLayoutA(LPCSTR pwszKLID
, UINT Flags
)
1576 UNICODE_STRING pwszKLIDW
;
1578 if (pwszKLID
) RtlCreateUnicodeStringFromAsciiz(&pwszKLIDW
, pwszKLID
);
1579 else pwszKLIDW
.Buffer
= NULL
;
1581 ret
= LoadKeyboardLayoutW(pwszKLIDW
.Buffer
, Flags
);
1582 RtlFreeUnicodeString(&pwszKLIDW
);
1587 /***********************************************************************
1588 * UnloadKeyboardLayout (USER32.@)
1590 BOOL WINAPI
UnloadKeyboardLayout( HKL layout
)
1592 FIXME_(keyboard
)( "layout %p, stub!\n", layout
);
1593 SetLastError( ERROR_CALL_NOT_IMPLEMENTED
);
1597 typedef struct __TRACKINGLIST
{
1598 TRACKMOUSEEVENT tme
;
1599 POINT pos
; /* center of hover rectangle */
1602 /* FIXME: move tracking stuff into a per thread data */
1603 static _TRACKINGLIST tracking_info
;
1604 static UINT_PTR timer
;
1606 static void check_mouse_leave(HWND hwnd
, int hittest
)
1608 if (tracking_info
.tme
.hwndTrack
!= hwnd
)
1610 if (tracking_info
.tme
.dwFlags
& TME_NONCLIENT
)
1611 PostMessageW(tracking_info
.tme
.hwndTrack
, WM_NCMOUSELEAVE
, 0, 0);
1613 PostMessageW(tracking_info
.tme
.hwndTrack
, WM_MOUSELEAVE
, 0, 0);
1615 /* remove the TME_LEAVE flag */
1616 tracking_info
.tme
.dwFlags
&= ~TME_LEAVE
;
1620 if (hittest
== HTCLIENT
)
1622 if (tracking_info
.tme
.dwFlags
& TME_NONCLIENT
)
1624 PostMessageW(tracking_info
.tme
.hwndTrack
, WM_NCMOUSELEAVE
, 0, 0);
1625 /* remove the TME_LEAVE flag */
1626 tracking_info
.tme
.dwFlags
&= ~TME_LEAVE
;
1631 if (!(tracking_info
.tme
.dwFlags
& TME_NONCLIENT
))
1633 PostMessageW(tracking_info
.tme
.hwndTrack
, WM_MOUSELEAVE
, 0, 0);
1634 /* remove the TME_LEAVE flag */
1635 tracking_info
.tme
.dwFlags
&= ~TME_LEAVE
;
1641 static void CALLBACK
TrackMouseEventProc(HWND hwnd
, UINT uMsg
, UINT_PTR idEvent
,
1645 INT hoverwidth
= 0, hoverheight
= 0, hittest
;
1647 TRACE("hwnd %p, msg %04x, id %04lx, time %u\n", hwnd
, uMsg
, idEvent
, dwTime
);
1650 hwnd
= WINPOS_WindowFromPoint(hwnd
, pos
, &hittest
);
1652 TRACE("point %s hwnd %p hittest %d\n", wine_dbgstr_point(&pos
), hwnd
, hittest
);
1654 SystemParametersInfoW(SPI_GETMOUSEHOVERWIDTH
, 0, &hoverwidth
, 0);
1655 SystemParametersInfoW(SPI_GETMOUSEHOVERHEIGHT
, 0, &hoverheight
, 0);
1657 TRACE("tracked pos %s, current pos %s, hover width %d, hover height %d\n",
1658 wine_dbgstr_point(&tracking_info
.pos
), wine_dbgstr_point(&pos
),
1659 hoverwidth
, hoverheight
);
1661 /* see if this tracking event is looking for TME_LEAVE and that the */
1662 /* mouse has left the window */
1663 if (tracking_info
.tme
.dwFlags
& TME_LEAVE
)
1665 check_mouse_leave(hwnd
, hittest
);
1668 if (tracking_info
.tme
.hwndTrack
!= hwnd
)
1670 /* mouse is gone, stop tracking mouse hover */
1671 tracking_info
.tme
.dwFlags
&= ~TME_HOVER
;
1674 /* see if we are tracking hovering for this hwnd */
1675 if (tracking_info
.tme
.dwFlags
& TME_HOVER
)
1677 /* has the cursor moved outside the rectangle centered around pos? */
1678 if ((abs(pos
.x
- tracking_info
.pos
.x
) > (hoverwidth
/ 2)) ||
1679 (abs(pos
.y
- tracking_info
.pos
.y
) > (hoverheight
/ 2)))
1681 /* record this new position as the current position */
1682 tracking_info
.pos
= pos
;
1686 if (hittest
== HTCLIENT
)
1688 ScreenToClient(hwnd
, &pos
);
1689 TRACE("client cursor pos %s\n", wine_dbgstr_point(&pos
));
1691 PostMessageW(tracking_info
.tme
.hwndTrack
, WM_MOUSEHOVER
,
1692 get_key_state(), MAKELPARAM( pos
.x
, pos
.y
));
1696 if (tracking_info
.tme
.dwFlags
& TME_NONCLIENT
)
1697 PostMessageW(tracking_info
.tme
.hwndTrack
, WM_NCMOUSEHOVER
,
1698 hittest
, MAKELPARAM( pos
.x
, pos
.y
));
1701 /* stop tracking mouse hover */
1702 tracking_info
.tme
.dwFlags
&= ~TME_HOVER
;
1706 /* stop the timer if the tracking list is empty */
1707 if (!(tracking_info
.tme
.dwFlags
& (TME_HOVER
| TME_LEAVE
)))
1709 KillSystemTimer(tracking_info
.tme
.hwndTrack
, timer
);
1711 tracking_info
.tme
.hwndTrack
= 0;
1712 tracking_info
.tme
.dwFlags
= 0;
1713 tracking_info
.tme
.dwHoverTime
= 0;
1718 /***********************************************************************
1719 * TrackMouseEvent [USER32]
1721 * Requests notification of mouse events
1723 * During mouse tracking WM_MOUSEHOVER or WM_MOUSELEAVE events are posted
1724 * to the hwnd specified in the ptme structure. After the event message
1725 * is posted to the hwnd, the entry in the queue is removed.
1727 * If the current hwnd isn't ptme->hwndTrack the TME_HOVER flag is completely
1728 * ignored. The TME_LEAVE flag results in a WM_MOUSELEAVE message being posted
1729 * immediately and the TME_LEAVE flag being ignored.
1732 * ptme [I,O] pointer to TRACKMOUSEEVENT information structure.
1741 TrackMouseEvent (TRACKMOUSEEVENT
*ptme
)
1748 TRACE("%x, %x, %p, %u\n", ptme
->cbSize
, ptme
->dwFlags
, ptme
->hwndTrack
, ptme
->dwHoverTime
);
1750 if (ptme
->cbSize
!= sizeof(TRACKMOUSEEVENT
)) {
1751 WARN("wrong TRACKMOUSEEVENT size from app\n");
1752 SetLastError(ERROR_INVALID_PARAMETER
);
1756 /* fill the TRACKMOUSEEVENT struct with the current tracking for the given hwnd */
1757 if (ptme
->dwFlags
& TME_QUERY
)
1759 *ptme
= tracking_info
.tme
;
1760 /* set cbSize in the case it's not initialized yet */
1761 ptme
->cbSize
= sizeof(TRACKMOUSEEVENT
);
1763 return TRUE
; /* return here, TME_QUERY is retrieving information */
1766 if (!IsWindow(ptme
->hwndTrack
))
1768 SetLastError(ERROR_INVALID_WINDOW_HANDLE
);
1772 hover_time
= (ptme
->dwFlags
& TME_HOVER
) ? ptme
->dwHoverTime
: HOVER_DEFAULT
;
1774 /* if HOVER_DEFAULT was specified replace this with the system's current value.
1775 * TME_LEAVE doesn't need to specify hover time so use default */
1776 if (hover_time
== HOVER_DEFAULT
|| hover_time
== 0)
1777 SystemParametersInfoW(SPI_GETMOUSEHOVERTIME
, 0, &hover_time
, 0);
1780 hwnd
= WINPOS_WindowFromPoint(ptme
->hwndTrack
, pos
, &hittest
);
1781 TRACE("point %s hwnd %p hittest %d\n", wine_dbgstr_point(&pos
), hwnd
, hittest
);
1783 if (ptme
->dwFlags
& ~(TME_CANCEL
| TME_HOVER
| TME_LEAVE
| TME_NONCLIENT
))
1784 FIXME("Unknown flag(s) %08x\n", ptme
->dwFlags
& ~(TME_CANCEL
| TME_HOVER
| TME_LEAVE
| TME_NONCLIENT
));
1786 if (ptme
->dwFlags
& TME_CANCEL
)
1788 if (tracking_info
.tme
.hwndTrack
== ptme
->hwndTrack
)
1790 tracking_info
.tme
.dwFlags
&= ~(ptme
->dwFlags
& ~TME_CANCEL
);
1792 /* if we aren't tracking on hover or leave remove this entry */
1793 if (!(tracking_info
.tme
.dwFlags
& (TME_HOVER
| TME_LEAVE
)))
1795 KillSystemTimer(tracking_info
.tme
.hwndTrack
, timer
);
1797 tracking_info
.tme
.hwndTrack
= 0;
1798 tracking_info
.tme
.dwFlags
= 0;
1799 tracking_info
.tme
.dwHoverTime
= 0;
1803 /* In our implementation it's possible that another window will receive a
1804 * WM_MOUSEMOVE and call TrackMouseEvent before TrackMouseEventProc is
1805 * called. In such a situation post the WM_MOUSELEAVE now */
1806 if (tracking_info
.tme
.dwFlags
& TME_LEAVE
&& tracking_info
.tme
.hwndTrack
!= NULL
)
1807 check_mouse_leave(hwnd
, hittest
);
1811 KillSystemTimer(tracking_info
.tme
.hwndTrack
, timer
);
1813 tracking_info
.tme
.hwndTrack
= 0;
1814 tracking_info
.tme
.dwFlags
= 0;
1815 tracking_info
.tme
.dwHoverTime
= 0;
1818 if (ptme
->hwndTrack
== hwnd
)
1820 /* Adding new mouse event to the tracking list */
1821 tracking_info
.tme
= *ptme
;
1822 tracking_info
.tme
.dwHoverTime
= hover_time
;
1824 /* Initialize HoverInfo variables even if not hover tracking */
1825 tracking_info
.pos
= pos
;
1827 timer
= SetSystemTimer(tracking_info
.tme
.hwndTrack
, (UINT_PTR
)&tracking_info
.tme
, hover_time
, TrackMouseEventProc
);
1834 /***********************************************************************
1835 * GetMouseMovePointsEx [USER32]
1838 * Success: count of point set in the buffer
1841 int WINAPI
GetMouseMovePointsEx( UINT size
, LPMOUSEMOVEPOINT ptin
, LPMOUSEMOVEPOINT ptout
, int count
, DWORD resolution
)
1843 cursor_pos_t
*pos
, positions
[64];
1848 TRACE( "%d, %p, %p, %d, %d\n", size
, ptin
, ptout
, count
, resolution
);
1850 if ((size
!= sizeof(MOUSEMOVEPOINT
)) || (count
< 0) || (count
> ARRAY_SIZE( positions
)))
1852 SetLastError( ERROR_INVALID_PARAMETER
);
1856 if (!ptin
|| (!ptout
&& count
))
1858 SetLastError( ERROR_NOACCESS
);
1862 if (resolution
!= GMMP_USE_DISPLAY_POINTS
)
1864 FIXME( "only GMMP_USE_DISPLAY_POINTS is supported for now\n" );
1865 SetLastError( ERROR_POINT_NOT_FOUND
);
1869 SERVER_START_REQ( get_cursor_history
)
1871 wine_server_set_reply( req
, &positions
, sizeof(positions
) );
1872 if (wine_server_call_err( req
)) return -1;
1876 for (i
= 0; i
< ARRAY_SIZE( positions
); i
++)
1878 pos
= &positions
[i
];
1879 if (ptin
->x
== pos
->x
&& ptin
->y
== pos
->y
&& (!ptin
->time
|| ptin
->time
== pos
->time
))
1883 if (i
== ARRAY_SIZE( positions
))
1885 SetLastError( ERROR_POINT_NOT_FOUND
);
1889 for (copied
= 0; copied
< count
&& i
< ARRAY_SIZE( positions
); copied
++, i
++)
1891 pos
= &positions
[i
];
1892 ptout
[copied
].x
= pos
->x
;
1893 ptout
[copied
].y
= pos
->y
;
1894 ptout
[copied
].time
= pos
->time
;
1895 ptout
[copied
].dwExtraInfo
= pos
->info
;
1901 /***********************************************************************
1902 * EnableMouseInPointer (USER32.@)
1904 BOOL WINAPI
EnableMouseInPointer(BOOL enable
)
1906 FIXME("(%#x) stub\n", enable
);
1908 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1912 static DWORD CALLBACK
devnotify_window_callback(HANDLE handle
, DWORD flags
, DEV_BROADCAST_HDR
*header
)
1914 SendMessageTimeoutW(handle
, WM_DEVICECHANGE
, flags
, (LPARAM
)header
, SMTO_ABORTIFHUNG
, 2000, NULL
);
1918 static DWORD CALLBACK
devnotify_service_callback(HANDLE handle
, DWORD flags
, DEV_BROADCAST_HDR
*header
)
1920 FIXME("Support for service handles is not yet implemented!\n");
1924 struct device_notification_details
1926 DWORD (CALLBACK
*cb
)(HANDLE handle
, DWORD flags
, DEV_BROADCAST_HDR
*header
);
1930 extern HDEVNOTIFY WINAPI
I_ScRegisterDeviceNotification( struct device_notification_details
*details
,
1931 void *filter
, DWORD flags
);
1932 extern BOOL WINAPI
I_ScUnregisterDeviceNotification( HDEVNOTIFY handle
);
1934 /***********************************************************************
1935 * RegisterDeviceNotificationA (USER32.@)
1937 * See RegisterDeviceNotificationW.
1939 HDEVNOTIFY WINAPI
RegisterDeviceNotificationA(HANDLE hRecipient
, LPVOID pNotificationFilter
, DWORD dwFlags
)
1941 TRACE("(hwnd=%p, filter=%p,flags=0x%08x)\n",
1942 hRecipient
,pNotificationFilter
,dwFlags
);
1943 if (pNotificationFilter
)
1944 FIXME("The notification filter will requires an A->W when filter support is implemented\n");
1945 return RegisterDeviceNotificationW(hRecipient
, pNotificationFilter
, dwFlags
);
1948 /***********************************************************************
1949 * RegisterDeviceNotificationW (USER32.@)
1951 HDEVNOTIFY WINAPI
RegisterDeviceNotificationW( HANDLE handle
, void *filter
, DWORD flags
)
1953 struct device_notification_details details
;
1955 TRACE("handle %p, filter %p, flags %#x\n", handle
, filter
, flags
);
1957 if (flags
& ~(DEVICE_NOTIFY_SERVICE_HANDLE
| DEVICE_NOTIFY_ALL_INTERFACE_CLASSES
))
1958 FIXME("unhandled flags %#x\n", flags
);
1960 details
.handle
= handle
;
1962 if (flags
& DEVICE_NOTIFY_SERVICE_HANDLE
)
1963 details
.cb
= devnotify_service_callback
;
1965 details
.cb
= devnotify_window_callback
;
1967 return I_ScRegisterDeviceNotification( &details
, filter
, 0 );
1970 /***********************************************************************
1971 * UnregisterDeviceNotification (USER32.@)
1973 BOOL WINAPI
UnregisterDeviceNotification( HDEVNOTIFY handle
)
1975 TRACE("%p\n", handle
);
1977 return I_ScUnregisterDeviceNotification( handle
);