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 BOOL
set_capture_window( HWND hwnd
, UINT gui_flags
, HWND
*prev_ret
)
126 if (gui_flags
& GUI_INMENUMODE
) flags
|= CAPTURE_MENU
;
127 if (gui_flags
& GUI_INMOVESIZE
) flags
|= CAPTURE_MOVESIZE
;
129 SERVER_START_REQ( set_capture_window
)
131 req
->handle
= wine_server_user_handle( hwnd
);
133 if ((ret
= !wine_server_call_err( req
)))
135 previous
= wine_server_ptr_handle( reply
->previous
);
136 hwnd
= wine_server_ptr_handle( reply
->full_handle
);
143 USER_Driver
->pSetCapture( hwnd
, gui_flags
);
146 SendMessageW( previous
, WM_CAPTURECHANGED
, 0, (LPARAM
)hwnd
);
148 if (prev_ret
) *prev_ret
= previous
;
154 /***********************************************************************
155 * __wine_send_input (USER32.@)
157 * Internal SendInput function to allow the graphics driver to inject real events.
159 BOOL CDECL
__wine_send_input( HWND hwnd
, const INPUT
*input
, const RAWINPUT
*rawinput
)
161 NTSTATUS status
= send_hardware_message( hwnd
, input
, rawinput
, 0 );
162 if (status
) SetLastError( RtlNtStatusToDosError(status
) );
167 /***********************************************************************
168 * update_mouse_coords
170 * Helper for SendInput.
172 static void update_mouse_coords( INPUT
*input
)
174 if (!(input
->u
.mi
.dwFlags
& MOUSEEVENTF_MOVE
)) return;
176 if (input
->u
.mi
.dwFlags
& MOUSEEVENTF_ABSOLUTE
)
178 DPI_AWARENESS_CONTEXT context
= SetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE
);
179 if (input
->u
.mi
.dwFlags
& MOUSEEVENTF_VIRTUALDESK
)
181 RECT rc
= get_virtual_screen_rect();
182 input
->u
.mi
.dx
= rc
.left
+ ((input
->u
.mi
.dx
* (rc
.right
- rc
.left
)) >> 16);
183 input
->u
.mi
.dy
= rc
.top
+ ((input
->u
.mi
.dy
* (rc
.bottom
- rc
.top
)) >> 16);
187 input
->u
.mi
.dx
= (input
->u
.mi
.dx
* GetSystemMetrics( SM_CXSCREEN
)) >> 16;
188 input
->u
.mi
.dy
= (input
->u
.mi
.dy
* GetSystemMetrics( SM_CYSCREEN
)) >> 16;
190 SetThreadDpiAwarenessContext( context
);
196 /* dx and dy can be negative numbers for relative movements */
197 SystemParametersInfoW(SPI_GETMOUSE
, 0, accel
, 0);
199 if (!accel
[2]) return;
201 if (abs(input
->u
.mi
.dx
) > accel
[0])
204 if ((abs(input
->u
.mi
.dx
) > accel
[1]) && (accel
[2] == 2)) input
->u
.mi
.dx
*= 2;
206 if (abs(input
->u
.mi
.dy
) > accel
[0])
209 if ((abs(input
->u
.mi
.dy
) > accel
[1]) && (accel
[2] == 2)) input
->u
.mi
.dy
*= 2;
214 /***********************************************************************
215 * SendInput (USER32.@)
217 UINT WINAPI
SendInput( UINT count
, LPINPUT inputs
, int size
)
220 NTSTATUS status
= STATUS_SUCCESS
;
222 if (size
!= sizeof(INPUT
))
224 SetLastError( ERROR_INVALID_PARAMETER
);
230 SetLastError( ERROR_INVALID_PARAMETER
);
236 SetLastError( ERROR_NOACCESS
);
240 for (i
= 0; i
< count
; i
++)
242 INPUT input
= inputs
[i
];
246 /* we need to update the coordinates to what the server expects */
247 update_mouse_coords( &input
);
250 status
= send_hardware_message( 0, &input
, NULL
, SEND_HWMSG_INJECTED
);
253 SetLastError( ERROR_CALL_NOT_IMPLEMENTED
);
259 SetLastError( RtlNtStatusToDosError(status
) );
268 /***********************************************************************
269 * keybd_event (USER32.@)
271 void WINAPI
keybd_event( BYTE bVk
, BYTE bScan
,
272 DWORD dwFlags
, ULONG_PTR dwExtraInfo
)
276 input
.type
= INPUT_KEYBOARD
;
277 input
.u
.ki
.wVk
= bVk
;
278 input
.u
.ki
.wScan
= bScan
;
279 input
.u
.ki
.dwFlags
= dwFlags
;
281 input
.u
.ki
.dwExtraInfo
= dwExtraInfo
;
282 SendInput( 1, &input
, sizeof(input
) );
286 /***********************************************************************
287 * mouse_event (USER32.@)
289 void WINAPI
mouse_event( DWORD dwFlags
, DWORD dx
, DWORD dy
,
290 DWORD dwData
, ULONG_PTR dwExtraInfo
)
294 input
.type
= INPUT_MOUSE
;
297 input
.u
.mi
.mouseData
= dwData
;
298 input
.u
.mi
.dwFlags
= dwFlags
;
300 input
.u
.mi
.dwExtraInfo
= dwExtraInfo
;
301 SendInput( 1, &input
, sizeof(input
) );
305 /***********************************************************************
306 * GetCursorPos (USER32.@)
308 BOOL WINAPI DECLSPEC_HOTPATCH
GetCursorPos( POINT
*pt
)
314 if (!pt
) return FALSE
;
316 SERVER_START_REQ( set_cursor
)
318 if ((ret
= !wine_server_call( req
)))
320 pt
->x
= reply
->new_x
;
321 pt
->y
= reply
->new_y
;
322 last_change
= reply
->last_change
;
327 /* query new position from graphics driver if we haven't updated recently */
328 if (ret
&& GetTickCount() - last_change
> 100) ret
= USER_Driver
->pGetCursorPos( pt
);
329 if (ret
&& (dpi
= get_thread_dpi()))
331 DPI_AWARENESS_CONTEXT context
;
332 context
= SetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE
);
333 *pt
= map_dpi_point( *pt
, get_monitor_dpi( MonitorFromPoint( *pt
, MONITOR_DEFAULTTOPRIMARY
)), dpi
);
334 SetThreadDpiAwarenessContext( context
);
340 /***********************************************************************
341 * GetCursorInfo (USER32.@)
343 BOOL WINAPI
GetCursorInfo( PCURSORINFO pci
)
347 if (!pci
) return FALSE
;
349 SERVER_START_REQ( get_thread_input
)
352 if ((ret
= !wine_server_call( req
)))
354 pci
->hCursor
= wine_server_ptr_handle( reply
->cursor
);
355 pci
->flags
= (reply
->show_count
>= 0) ? CURSOR_SHOWING
: 0;
359 GetCursorPos(&pci
->ptScreenPos
);
364 /***********************************************************************
365 * SetCursorPos (USER32.@)
367 BOOL WINAPI DECLSPEC_HOTPATCH
SetCursorPos( INT x
, INT y
)
371 INT prev_x
, prev_y
, new_x
, new_y
;
374 if ((dpi
= get_thread_dpi()))
375 pt
= map_dpi_point( pt
, dpi
, get_monitor_dpi( MonitorFromPoint( pt
, MONITOR_DEFAULTTOPRIMARY
)));
377 SERVER_START_REQ( set_cursor
)
379 req
->flags
= SET_CURSOR_POS
;
382 if ((ret
= !wine_server_call( req
)))
384 prev_x
= reply
->prev_x
;
385 prev_y
= reply
->prev_y
;
386 new_x
= reply
->new_x
;
387 new_y
= reply
->new_y
;
391 if (ret
&& (prev_x
!= new_x
|| prev_y
!= new_y
)) USER_Driver
->pSetCursorPos( new_x
, new_y
);
395 /**********************************************************************
396 * SetCapture (USER32.@)
398 HWND WINAPI DECLSPEC_HOTPATCH
SetCapture( HWND hwnd
)
402 set_capture_window( hwnd
, 0, &previous
);
407 /**********************************************************************
408 * ReleaseCapture (USER32.@)
410 BOOL WINAPI DECLSPEC_HOTPATCH
ReleaseCapture(void)
412 BOOL ret
= set_capture_window( 0, 0, NULL
);
414 /* Somebody may have missed some mouse movements */
415 if (ret
) mouse_event( MOUSEEVENTF_MOVE
, 0, 0, 0, 0 );
421 /**********************************************************************
422 * GetCapture (USER32.@)
424 HWND WINAPI
GetCapture(void)
428 SERVER_START_REQ( get_thread_input
)
430 req
->tid
= GetCurrentThreadId();
431 if (!wine_server_call_err( req
)) ret
= wine_server_ptr_handle( reply
->capture
);
438 static void check_for_events( UINT flags
)
440 if (USER_Driver
->pMsgWaitForMultipleObjectsEx( 0, NULL
, 0, flags
, 0 ) == WAIT_TIMEOUT
)
441 flush_window_surfaces( TRUE
);
444 /**********************************************************************
445 * GetAsyncKeyState (USER32.@)
447 * Determine if a key is or was pressed. retval has high-order
448 * bit set to 1 if currently pressed, low-order bit set to 1 if key has
451 SHORT WINAPI DECLSPEC_HOTPATCH
GetAsyncKeyState( INT key
)
453 struct user_key_state_info
*key_state_info
= get_user_thread_info()->key_state
;
454 INT counter
= global_key_state_counter
;
458 if (key
< 0 || key
>= 256) return 0;
460 check_for_events( QS_INPUT
);
462 if (key_state_info
&& !(key_state_info
->state
[key
] & 0xc0) &&
463 key_state_info
->counter
== counter
&& GetTickCount() - key_state_info
->time
< 50)
465 /* use cached value */
468 else if (!key_state_info
)
470 key_state_info
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*key_state_info
) );
471 get_user_thread_info()->key_state
= key_state_info
;
475 SERVER_START_REQ( get_key_state
)
481 prev_key_state
= key_state_info
->state
[key
];
482 wine_server_set_reply( req
, key_state_info
->state
, sizeof(key_state_info
->state
) );
484 if (!wine_server_call( req
))
486 if (reply
->state
& 0x40) ret
|= 0x0001;
487 if (reply
->state
& 0x80) ret
|= 0x8000;
490 /* force refreshing the key state cache - some multithreaded programs
491 * (like Adobe Photoshop CS5) expect that changes to the async key state
492 * are also immediately available in other threads. */
493 if (prev_key_state
!= key_state_info
->state
[key
])
494 counter
= InterlockedIncrement( &global_key_state_counter
);
496 key_state_info
->time
= GetTickCount();
497 key_state_info
->counter
= counter
;
507 /***********************************************************************
508 * GetQueueStatus (USER32.@)
510 DWORD WINAPI
GetQueueStatus( UINT flags
)
514 if (flags
& ~(QS_ALLINPUT
| QS_ALLPOSTMESSAGE
| QS_SMRESULT
))
516 SetLastError( ERROR_INVALID_FLAGS
);
520 check_for_events( flags
);
522 SERVER_START_REQ( get_queue_status
)
524 req
->clear_bits
= flags
;
525 wine_server_call( req
);
526 ret
= MAKELONG( reply
->changed_bits
& flags
, reply
->wake_bits
& flags
);
533 /***********************************************************************
534 * GetInputState (USER32.@)
536 BOOL WINAPI
GetInputState(void)
540 check_for_events( QS_INPUT
);
542 SERVER_START_REQ( get_queue_status
)
545 wine_server_call( req
);
546 ret
= reply
->wake_bits
& (QS_KEY
| QS_MOUSEBUTTON
);
553 /******************************************************************
554 * GetLastInputInfo (USER32.@)
556 BOOL WINAPI
GetLastInputInfo(PLASTINPUTINFO plii
)
562 if (plii
->cbSize
!= sizeof (*plii
) )
564 SetLastError(ERROR_INVALID_PARAMETER
);
568 SERVER_START_REQ( get_last_input_time
)
570 ret
= !wine_server_call_err( req
);
572 plii
->dwTime
= reply
->time
;
579 /**********************************************************************
580 * AttachThreadInput (USER32.@)
582 * Attaches the input processing mechanism of one thread to that of
585 BOOL WINAPI
AttachThreadInput( DWORD from
, DWORD to
, BOOL attach
)
589 SERVER_START_REQ( attach_thread_input
)
591 req
->tid_from
= from
;
593 req
->attach
= attach
;
594 ret
= !wine_server_call_err( req
);
601 /**********************************************************************
602 * GetKeyState (USER32.@)
604 * An application calls the GetKeyState function in response to a
605 * keyboard-input message. This function retrieves the state of the key
606 * at the time the input message was generated.
608 SHORT WINAPI DECLSPEC_HOTPATCH
GetKeyState(INT vkey
)
612 SERVER_START_REQ( get_key_state
)
615 if (!wine_server_call( req
)) retval
= (signed char)(reply
->state
& 0x81);
618 TRACE("key (0x%x) -> %x\n", vkey
, retval
);
623 /**********************************************************************
624 * GetKeyboardState (USER32.@)
626 BOOL WINAPI DECLSPEC_HOTPATCH
GetKeyboardState( LPBYTE state
)
631 TRACE("(%p)\n", state
);
633 memset( state
, 0, 256 );
634 SERVER_START_REQ( get_key_state
)
637 wine_server_set_reply( req
, state
, 256 );
638 ret
= !wine_server_call_err( req
);
639 for (i
= 0; i
< 256; i
++) state
[i
] &= 0x81;
646 /**********************************************************************
647 * SetKeyboardState (USER32.@)
649 BOOL WINAPI
SetKeyboardState( LPBYTE state
)
653 SERVER_START_REQ( set_key_state
)
655 wine_server_add_data( req
, state
, 256 );
656 ret
= !wine_server_call_err( req
);
663 /**********************************************************************
664 * VkKeyScanA (USER32.@)
666 * VkKeyScan translates an ANSI character to a virtual-key and shift code
667 * for the current keyboard.
668 * high-order byte yields :
672 * 3-5 Shift-key combinations that are not used for characters
675 * I.e. : Shift = 1, Ctrl = 2, Alt = 4.
676 * FIXME : works ok except for dead chars :
677 * VkKeyScan '^'(0x5e, 94) ... got keycode 00 ... returning 00
678 * VkKeyScan '`'(0x60, 96) ... got keycode 00 ... returning 00
680 SHORT WINAPI
VkKeyScanA(CHAR cChar
)
684 if (IsDBCSLeadByte(cChar
)) return -1;
686 MultiByteToWideChar(CP_ACP
, 0, &cChar
, 1, &wChar
, 1);
687 return VkKeyScanW(wChar
);
690 /******************************************************************************
691 * VkKeyScanW (USER32.@)
693 SHORT WINAPI
VkKeyScanW(WCHAR cChar
)
695 return VkKeyScanExW(cChar
, GetKeyboardLayout(0));
698 /**********************************************************************
699 * VkKeyScanExA (USER32.@)
701 WORD WINAPI
VkKeyScanExA(CHAR cChar
, HKL dwhkl
)
705 if (IsDBCSLeadByte(cChar
)) return -1;
707 MultiByteToWideChar(CP_ACP
, 0, &cChar
, 1, &wChar
, 1);
708 return VkKeyScanExW(wChar
, dwhkl
);
711 /******************************************************************************
712 * VkKeyScanExW (USER32.@)
714 WORD WINAPI
VkKeyScanExW( WCHAR chr
, HKL layout
)
716 WORD shift
= 0x100, ctrl
= 0x200;
719 TRACE_(keyboard
)( "chr %s, layout %p\n", debugstr_wn(&chr
, 1), layout
);
721 if ((ret
= USER_Driver
->pVkKeyScanEx( chr
, layout
)) != -256) return ret
;
723 /* FIXME: English keyboard layout specific */
725 if (chr
== VK_CANCEL
|| chr
== VK_BACK
|| chr
== VK_TAB
|| chr
== VK_RETURN
||
726 chr
== VK_ESCAPE
|| chr
== VK_SPACE
) ret
= chr
;
727 else if (chr
>= '0' && chr
<= '9') ret
= chr
;
728 else if (chr
== ')') ret
= shift
+ '0';
729 else if (chr
== '!') ret
= shift
+ '1';
730 else if (chr
== '@') ret
= shift
+ '2';
731 else if (chr
== '#') ret
= shift
+ '3';
732 else if (chr
== '$') ret
= shift
+ '4';
733 else if (chr
== '%') ret
= shift
+ '5';
734 else if (chr
== '^') ret
= shift
+ '6';
735 else if (chr
== '&') ret
= shift
+ '7';
736 else if (chr
== '*') ret
= shift
+ '8';
737 else if (chr
== '(') ret
= shift
+ '9';
738 else if (chr
>= 'a' && chr
<= 'z') ret
= chr
- 'a' + 'A';
739 else if (chr
>= 'A' && chr
<= 'Z') ret
= shift
+ chr
;
740 else if (chr
== ';') ret
= VK_OEM_1
;
741 else if (chr
== '=') ret
= VK_OEM_PLUS
;
742 else if (chr
== ',') ret
= VK_OEM_COMMA
;
743 else if (chr
== '-') ret
= VK_OEM_MINUS
;
744 else if (chr
== '.') ret
= VK_OEM_PERIOD
;
745 else if (chr
== '/') ret
= VK_OEM_2
;
746 else if (chr
== '`') ret
= VK_OEM_3
;
747 else if (chr
== '[') ret
= VK_OEM_4
;
748 else if (chr
== '\\') ret
= VK_OEM_5
;
749 else if (chr
== ']') ret
= VK_OEM_6
;
750 else if (chr
== '\'') ret
= VK_OEM_7
;
751 else if (chr
== ':') ret
= shift
+ VK_OEM_1
;
752 else if (chr
== '+') ret
= shift
+ VK_OEM_PLUS
;
753 else if (chr
== '<') ret
= shift
+ VK_OEM_COMMA
;
754 else if (chr
== '_') ret
= shift
+ VK_OEM_MINUS
;
755 else if (chr
== '>') ret
= shift
+ VK_OEM_PERIOD
;
756 else if (chr
== '?') ret
= shift
+ VK_OEM_2
;
757 else if (chr
== '~') ret
= shift
+ VK_OEM_3
;
758 else if (chr
== '{') ret
= shift
+ VK_OEM_4
;
759 else if (chr
== '|') ret
= shift
+ VK_OEM_5
;
760 else if (chr
== '}') ret
= shift
+ VK_OEM_6
;
761 else if (chr
== '\"') ret
= shift
+ VK_OEM_7
;
762 else if (chr
== 0x7f) ret
= ctrl
+ VK_BACK
;
763 else if (chr
== '\n') ret
= ctrl
+ VK_RETURN
;
764 else if (chr
== 0xf000) ret
= ctrl
+ '2';
765 else if (chr
== 0x0000) ret
= ctrl
+ shift
+ '2';
766 else if (chr
>= 0x0001 && chr
<= 0x001a) ret
= ctrl
+ 'A' + chr
- 1;
767 else if (chr
>= 0x001c && chr
<= 0x001d) ret
= ctrl
+ VK_OEM_3
+ chr
;
768 else if (chr
== 0x001e) ret
= ctrl
+ shift
+ '6';
769 else if (chr
== 0x001f) ret
= ctrl
+ shift
+ VK_OEM_MINUS
;
772 TRACE_(keyboard
)( "ret %04x\n", ret
);
776 /**********************************************************************
777 * OemKeyScan (USER32.@)
779 DWORD WINAPI
OemKeyScan( WORD oem
)
783 char oem_char
= LOBYTE( oem
);
785 if (!OemToCharBuffW( &oem_char
, &wchr
, 1 ))
788 vkey
= VkKeyScanW( wchr
);
789 scan
= MapVirtualKeyW( LOBYTE( vkey
), MAPVK_VK_TO_VSC
);
790 if (!scan
) return -1;
797 /******************************************************************************
798 * GetKeyboardType (USER32.@)
800 INT WINAPI
GetKeyboardType(INT nTypeFlag
)
802 TRACE_(keyboard
)("(%d)\n", nTypeFlag
);
803 if (LOWORD(GetKeyboardLayout(0)) == MAKELANGID(LANG_JAPANESE
, SUBLANG_JAPANESE_JAPAN
))
805 /* scan code for `_', the key left of r-shift, in Japanese 106 keyboard */
806 const UINT JP106_VSC_USCORE
= 0x73;
810 case 0: /* Keyboard type */
811 return 7; /* Japanese keyboard */
812 case 1: /* Keyboard Subtype */
813 /* Test keyboard mappings to detect Japanese keyboard */
814 if (MapVirtualKeyW(VK_OEM_102
, MAPVK_VK_TO_VSC
) == JP106_VSC_USCORE
815 && MapVirtualKeyW(JP106_VSC_USCORE
, MAPVK_VSC_TO_VK
) == VK_OEM_102
)
816 return 2; /* Japanese 106 */
818 return 0; /* AT-101 */
819 case 2: /* Number of F-keys */
820 return 12; /* It has 12 F-keys */
827 case 0: /* Keyboard type */
828 return 4; /* AT-101 */
829 case 1: /* Keyboard Subtype */
830 return 0; /* There are no defined subtypes */
831 case 2: /* Number of F-keys */
832 return 12; /* We're doing an 101 for now, so return 12 F-keys */
835 WARN_(keyboard
)("Unknown type\n");
836 return 0; /* The book says 0 here, so 0 */
839 /******************************************************************************
840 * MapVirtualKeyA (USER32.@)
842 UINT WINAPI
MapVirtualKeyA(UINT code
, UINT maptype
)
844 return MapVirtualKeyExA( code
, maptype
, GetKeyboardLayout(0) );
847 /******************************************************************************
848 * MapVirtualKeyW (USER32.@)
850 UINT WINAPI
MapVirtualKeyW(UINT code
, UINT maptype
)
852 return MapVirtualKeyExW(code
, maptype
, GetKeyboardLayout(0));
855 /******************************************************************************
856 * MapVirtualKeyExA (USER32.@)
858 UINT WINAPI
MapVirtualKeyExA(UINT code
, UINT maptype
, HKL hkl
)
862 ret
= MapVirtualKeyExW( code
, maptype
, hkl
);
863 if (maptype
== MAPVK_VK_TO_CHAR
)
868 WideCharToMultiByte( CP_ACP
, 0, &wch
, 1, (LPSTR
)&ch
, 1, NULL
, NULL
);
875 /* English keyboard layout (0x0409) */
876 static const UINT kbd_en_vsc2vk
[] =
878 0x00, 0x1b, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0xbd, 0xbb, 0x08, 0x09,
879 0x51, 0x57, 0x45, 0x52, 0x54, 0x59, 0x55, 0x49, 0x4f, 0x50, 0xdb, 0xdd, 0x0d, 0xa2, 0x41, 0x53,
880 0x44, 0x46, 0x47, 0x48, 0x4a, 0x4b, 0x4c, 0xba, 0xde, 0xc0, 0xa0, 0xdc, 0x5a, 0x58, 0x43, 0x56,
881 0x42, 0x4e, 0x4d, 0xbc, 0xbe, 0xbf, 0xa1, 0x6a, 0xa4, 0x20, 0x14, 0x70, 0x71, 0x72, 0x73, 0x74,
882 0x75, 0x76, 0x77, 0x78, 0x79, 0x90, 0x91, 0x24, 0x26, 0x21, 0x6d, 0x25, 0x0c, 0x27, 0x6b, 0x23,
883 0x28, 0x22, 0x2d, 0x2e, 0x2c, 0x00, 0xe2, 0x7a, 0x7b, 0x0c, 0xee, 0xf1, 0xea, 0xf9, 0xf5, 0xf3,
884 0x00, 0x00, 0xfb, 0x2f, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0xed,
885 0x00, 0xe9, 0x00, 0xc1, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, 0x00, 0xeb, 0x09, 0x00, 0xc2, 0x00,
886 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
887 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
888 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
889 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
890 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
891 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
892 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
893 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
895 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
896 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x0d, 0xa3, 0x00, 0x00,
897 0xad, 0xb7, 0xb3, 0x00, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xae, 0x00,
898 0xaf, 0x00, 0xac, 0x00, 0x00, 0x6f, 0x00, 0x2c, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
899 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x24, 0x26, 0x21, 0x00, 0x25, 0x00, 0x27, 0x00, 0x23,
900 0x28, 0x22, 0x2d, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5b, 0x5c, 0x5d, 0x00, 0x5f,
901 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xab, 0xa8, 0xa9, 0xa7, 0xa6, 0xb6, 0xb4, 0xb5, 0x00, 0x00,
902 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00,
914 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
915 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
916 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
917 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
918 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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,
930 static const UINT kbd_en_vk2char
[] =
932 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x08, 0x09, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00,
933 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00,
934 ' ', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
935 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
936 0x00, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
937 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 0x00, 0x00, 0x00, 0x00, 0x00,
938 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '*', '+', 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, ';', '=', ',', '-', '.', '/',
944 '`', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
945 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, '[', '\\', ']', '\'', 0x00,
946 0x00, 0x00, '\\', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
947 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
950 static const WCHAR
*kbd_en_vscname
[] =
952 0, L
"Esc", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, L
"Backspace", L
"Tab",
953 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, L
"Enter", L
"Ctrl", 0, 0,
954 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, L
"Shift", 0, 0, 0, 0, 0,
955 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",
956 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",
957 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,
958 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
959 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, L
"F13", L
"F14", L
"F15", L
"F16",
960 L
"F17", L
"F18", L
"F19", L
"F20", L
"F21", L
"F22", L
"F23", L
"F24", 0, 0, 0, 0, 0, 0, 0, 0,
961 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
962 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
963 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
964 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
965 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
966 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
967 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
969 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
970 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, L
"Num Enter", L
"Right Ctrl", 0, 0,
971 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
972 0, 0, 0, 0, 0, L
"Num /", 0, L
"Prnt Scrn", L
"Right Alt", 0, 0, 0, 0, 0, 0, 0,
973 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",
974 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,
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, 0, 0, 0, 0,
977 0, 0, 0, 0, 0, 0, 0, 0, 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,
988 /******************************************************************************
989 * MapVirtualKeyExW (USER32.@)
991 UINT WINAPI
MapVirtualKeyExW( UINT code
, UINT type
, HKL layout
)
993 const UINT
*vsc2vk
, *vk2char
;
994 UINT vsc2vk_size
, vk2char_size
;
997 TRACE_(keyboard
)( "code %u, type %u, layout %p.\n", code
, type
, layout
);
999 if ((ret
= USER_Driver
->pMapVirtualKeyEx( code
, type
, layout
)) != -1) return ret
;
1001 /* FIXME: English keyboard layout specific */
1003 vsc2vk
= kbd_en_vsc2vk
;
1004 vsc2vk_size
= ARRAYSIZE(kbd_en_vsc2vk
);
1005 vk2char
= kbd_en_vk2char
;
1006 vk2char_size
= ARRAYSIZE(kbd_en_vk2char
);
1010 case MAPVK_VK_TO_VSC_EX
:
1011 case MAPVK_VK_TO_VSC
:
1014 case VK_SHIFT
: code
= VK_LSHIFT
; break;
1015 case VK_CONTROL
: code
= VK_LCONTROL
; break;
1016 case VK_MENU
: code
= VK_LMENU
; break;
1017 case VK_NUMPAD0
: code
= VK_INSERT
; break;
1018 case VK_NUMPAD1
: code
= VK_END
; break;
1019 case VK_NUMPAD2
: code
= VK_DOWN
; break;
1020 case VK_NUMPAD3
: code
= VK_NEXT
; break;
1021 case VK_NUMPAD4
: code
= VK_LEFT
; break;
1022 case VK_NUMPAD5
: code
= VK_CLEAR
; break;
1023 case VK_NUMPAD6
: code
= VK_RIGHT
; break;
1024 case VK_NUMPAD7
: code
= VK_HOME
; break;
1025 case VK_NUMPAD8
: code
= VK_UP
; break;
1026 case VK_NUMPAD9
: code
= VK_PRIOR
; break;
1027 case VK_DECIMAL
: code
= VK_DELETE
; break;
1030 for (ret
= 0; ret
< vsc2vk_size
; ++ret
) if (vsc2vk
[ret
] == code
) break;
1031 if (ret
>= vsc2vk_size
) ret
= 0;
1033 if (type
== MAPVK_VK_TO_VSC
)
1035 if (ret
>= 0x200) ret
= 0;
1038 else if (ret
>= 0x100) ret
+= 0xdf00;
1040 case MAPVK_VSC_TO_VK
:
1041 case MAPVK_VSC_TO_VK_EX
:
1042 if (code
& 0xe000) code
-= 0xdf00;
1043 if (code
>= vsc2vk_size
) ret
= 0;
1044 else ret
= vsc2vk
[code
];
1046 if (type
== MAPVK_VSC_TO_VK
)
1050 case VK_LSHIFT
: case VK_RSHIFT
: ret
= VK_SHIFT
; break;
1051 case VK_LCONTROL
: case VK_RCONTROL
: ret
= VK_CONTROL
; break;
1052 case VK_LMENU
: case VK_RMENU
: ret
= VK_MENU
; break;
1056 case MAPVK_VK_TO_CHAR
:
1057 if (code
>= vk2char_size
) ret
= 0;
1058 else ret
= vk2char
[code
];
1061 FIXME_(keyboard
)( "unknown type %d\n", type
);
1065 TRACE_(keyboard
)( "returning 0x%04x\n", ret
);
1069 /****************************************************************************
1070 * GetKBCodePage (USER32.@)
1072 UINT WINAPI
GetKBCodePage(void)
1077 /***********************************************************************
1078 * GetKeyboardLayout (USER32.@)
1080 * - device handle for keyboard layout defaulted to
1081 * the language id. This is the way Windows default works.
1082 * - the thread identifier is also ignored.
1084 HKL WINAPI
GetKeyboardLayout(DWORD thread_id
)
1086 struct user_thread_info
*thread
= get_user_thread_info();
1087 HKL layout
= thread
->kbd_layout
;
1089 if (thread_id
&& thread_id
!= GetCurrentThreadId())
1090 FIXME( "couldn't return keyboard layout for thread %04x\n", thread_id
);
1092 if (!layout
) return get_locale_kbd_layout();
1096 /****************************************************************************
1097 * GetKeyboardLayoutNameA (USER32.@)
1099 BOOL WINAPI
GetKeyboardLayoutNameA(LPSTR pszKLID
)
1101 WCHAR buf
[KL_NAMELENGTH
];
1103 if (GetKeyboardLayoutNameW(buf
))
1104 return WideCharToMultiByte( CP_ACP
, 0, buf
, -1, pszKLID
, KL_NAMELENGTH
, NULL
, NULL
) != 0;
1108 /****************************************************************************
1109 * GetKeyboardLayoutNameW (USER32.@)
1111 BOOL WINAPI
GetKeyboardLayoutNameW(LPWSTR pwszKLID
)
1115 SetLastError(ERROR_NOACCESS
);
1118 return USER_Driver
->pGetKeyboardLayoutName(pwszKLID
);
1121 /****************************************************************************
1122 * GetKeyNameTextA (USER32.@)
1124 INT WINAPI
GetKeyNameTextA(LONG lParam
, LPSTR lpBuffer
, INT nSize
)
1129 if (!nSize
|| !GetKeyNameTextW(lParam
, buf
, 256))
1134 ret
= WideCharToMultiByte(CP_ACP
, 0, buf
, -1, lpBuffer
, nSize
, NULL
, NULL
);
1145 /****************************************************************************
1146 * GetKeyNameTextW (USER32.@)
1148 INT WINAPI
GetKeyNameTextW( LONG lparam
, LPWSTR buffer
, INT size
)
1150 INT code
= ((lparam
>> 16) & 0x1ff), vkey
, len
;
1151 UINT vsc2vk_size
, vscname_size
;
1152 const WCHAR
*const *vscname
;
1156 TRACE_(keyboard
)( "lparam %d, buffer %p, size %d.\n", lparam
, buffer
, size
);
1158 if (!buffer
|| !size
) return 0;
1159 if ((len
= USER_Driver
->pGetKeyNameText( lparam
, buffer
, size
)) >= 0) return len
;
1161 /* FIXME: English keyboard layout specific */
1163 vsc2vk
= kbd_en_vsc2vk
;
1164 vsc2vk_size
= ARRAYSIZE(kbd_en_vsc2vk
);
1165 vscname
= kbd_en_vscname
;
1166 vscname_size
= ARRAYSIZE(kbd_en_vscname
);
1168 if (lparam
& 0x2000000)
1170 switch ((vkey
= vsc2vk
[code
]))
1175 for (code
= 0; code
< vsc2vk_size
; ++code
)
1176 if (vsc2vk
[code
] == (vkey
- 1)) break;
1181 if (code
>= vscname_size
) buffer
[0] = 0;
1182 else if (vscname
[code
]) lstrcpynW( buffer
, vscname
[code
], size
);
1185 vkey
= MapVirtualKeyW( code
& 0xff, MAPVK_VSC_TO_VK
);
1186 tmp
[0] = MapVirtualKeyW( vkey
, MAPVK_VK_TO_CHAR
);
1188 lstrcpynW( buffer
, tmp
, size
);
1190 len
= wcslen( buffer
);
1192 TRACE_(keyboard
)( "ret %d, str %s.\n", len
, debugstr_w(buffer
) );
1196 /****************************************************************************
1197 * ToUnicode (USER32.@)
1199 INT WINAPI
ToUnicode(UINT virtKey
, UINT scanCode
, const BYTE
*lpKeyState
,
1200 LPWSTR lpwStr
, int size
, UINT flags
)
1202 return ToUnicodeEx(virtKey
, scanCode
, lpKeyState
, lpwStr
, size
, flags
, GetKeyboardLayout(0));
1205 /****************************************************************************
1206 * ToUnicodeEx (USER32.@)
1208 INT WINAPI
ToUnicodeEx( UINT virt
, UINT scan
, const BYTE
*state
,
1209 WCHAR
*str
, int size
, UINT flags
, HKL layout
)
1211 BOOL shift
, ctrl
, alt
, numlock
;
1215 TRACE_(keyboard
)( "virt %u, scan %u, state %p, str %p, size %d, flags %x, layout %p.\n",
1216 virt
, scan
, state
, str
, size
, flags
, layout
);
1218 if (!state
) return 0;
1219 if ((len
= USER_Driver
->pToUnicodeEx( virt
, scan
, state
, str
, size
, flags
, layout
)) >= -1) return len
;
1221 alt
= state
[VK_MENU
] & 0x80;
1222 shift
= state
[VK_SHIFT
] & 0x80;
1223 ctrl
= state
[VK_CONTROL
] & 0x80;
1224 numlock
= state
[VK_NUMLOCK
] & 0x01;
1226 /* FIXME: English keyboard layout specific */
1228 if (scan
& 0x8000) buffer
[0] = 0; /* key up */
1229 else if (virt
== VK_ESCAPE
) buffer
[0] = VK_ESCAPE
;
1234 case VK_BACK
: buffer
[0] = '\b'; break;
1235 case VK_OEM_1
: buffer
[0] = shift
? ':' : ';'; break;
1236 case VK_OEM_2
: buffer
[0] = shift
? '?' : '/'; break;
1237 case VK_OEM_3
: buffer
[0] = shift
? '~' : '`'; break;
1238 case VK_OEM_4
: buffer
[0] = shift
? '{' : '['; break;
1239 case VK_OEM_5
: buffer
[0] = shift
? '|' : '\\'; break;
1240 case VK_OEM_6
: buffer
[0] = shift
? '}' : ']'; break;
1241 case VK_OEM_7
: buffer
[0] = shift
? '"' : '\''; break;
1242 case VK_OEM_COMMA
: buffer
[0] = shift
? '<' : ','; break;
1243 case VK_OEM_MINUS
: buffer
[0] = shift
? '_' : '-'; break;
1244 case VK_OEM_PERIOD
: buffer
[0] = shift
? '>' : '.'; break;
1245 case VK_OEM_PLUS
: buffer
[0] = shift
? '+' : '='; break;
1246 case VK_RETURN
: buffer
[0] = '\r'; break;
1247 case VK_SPACE
: buffer
[0] = ' '; break;
1248 case VK_TAB
: buffer
[0] = '\t'; break;
1249 case VK_MULTIPLY
: buffer
[0] = '*'; break;
1250 case VK_ADD
: buffer
[0] = '+'; break;
1251 case VK_SUBTRACT
: buffer
[0] = '-'; break;
1252 case VK_DIVIDE
: buffer
[0] = '/'; break;
1254 if (virt
>= '0' && virt
<= '9')
1255 buffer
[0] = shift
? ")!@#$%^&*("[virt
- '0'] : virt
;
1256 else if (virt
>= 'A' && virt
<= 'Z')
1257 buffer
[0] = shift
|| (state
[VK_CAPITAL
] & 0x01) ? virt
: virt
+ 'a' - 'A';
1258 else if (virt
>= VK_NUMPAD0
&& virt
<= VK_NUMPAD9
&& numlock
&& !shift
)
1259 buffer
[0] = '0' + virt
- VK_NUMPAD0
;
1260 else if (virt
== VK_DECIMAL
&& numlock
&& !shift
)
1267 else if (!alt
) /* Control codes */
1271 case VK_OEM_4
: buffer
[0] = 0x1b; break;
1272 case VK_OEM_5
: buffer
[0] = 0x1c; break;
1273 case VK_OEM_6
: buffer
[0] = 0x1d; break;
1274 case VK_SUBTRACT
: buffer
[0] = 0x1e; break;
1275 case VK_RETURN
: buffer
[0] = shift
? 0 : '\n'; break;
1276 case VK_SPACE
: buffer
[0] = ' '; break;
1278 if (virt
>= 'A' && virt
<= 'Z') buffer
[0] = virt
- 'A' + 1;
1285 len
= wcslen( buffer
);
1286 lstrcpynW( str
, buffer
, size
);
1288 TRACE_(keyboard
)( "ret %d, str %s.\n", len
, debugstr_w(str
) );
1292 /****************************************************************************
1293 * ToAscii (USER32.@)
1295 INT WINAPI
ToAscii( UINT virtKey
, UINT scanCode
, const BYTE
*lpKeyState
,
1296 LPWORD lpChar
, UINT flags
)
1298 return ToAsciiEx(virtKey
, scanCode
, lpKeyState
, lpChar
, flags
, GetKeyboardLayout(0));
1301 /****************************************************************************
1302 * ToAsciiEx (USER32.@)
1304 INT WINAPI
ToAsciiEx( UINT virtKey
, UINT scanCode
, const BYTE
*lpKeyState
,
1305 LPWORD lpChar
, UINT flags
, HKL dwhkl
)
1310 ret
= ToUnicodeEx(virtKey
, scanCode
, lpKeyState
, uni_chars
, 2, flags
, dwhkl
);
1311 if (ret
< 0) n_ret
= 1; /* FIXME: make ToUnicode return 2 for dead chars */
1313 WideCharToMultiByte(CP_ACP
, 0, uni_chars
, n_ret
, (LPSTR
)lpChar
, 2, NULL
, NULL
);
1317 /**********************************************************************
1318 * ActivateKeyboardLayout (USER32.@)
1320 HKL WINAPI
ActivateKeyboardLayout( HKL layout
, UINT flags
)
1322 struct user_thread_info
*info
= get_user_thread_info();
1325 TRACE_(keyboard
)( "layout %p, flags %x\n", layout
, flags
);
1327 if (flags
) FIXME_(keyboard
)( "flags %x not supported\n", flags
);
1329 if (layout
== (HKL
)HKL_NEXT
|| layout
== (HKL
)HKL_PREV
)
1331 SetLastError( ERROR_CALL_NOT_IMPLEMENTED
);
1332 FIXME_(keyboard
)( "HKL_NEXT and HKL_PREV not supported\n" );
1336 if (!USER_Driver
->pActivateKeyboardLayout( layout
, flags
))
1339 old_layout
= info
->kbd_layout
;
1340 info
->kbd_layout
= layout
;
1342 if (!old_layout
) return get_locale_kbd_layout();
1346 /**********************************************************************
1347 * BlockInput (USER32.@)
1349 BOOL WINAPI
BlockInput(BOOL fBlockIt
)
1351 FIXME_(keyboard
)("(%d): stub\n", fBlockIt
);
1352 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1357 /***********************************************************************
1358 * GetKeyboardLayoutList (USER32.@)
1360 * Return number of values available if either input parm is
1361 * 0, per MS documentation.
1363 UINT WINAPI
GetKeyboardLayoutList( INT size
, HKL
*layouts
)
1365 WCHAR klid
[KL_NAMELENGTH
], value
[5];
1366 DWORD value_size
, count
, tmp
, i
= 0;
1370 TRACE_(keyboard
)( "size %d, layouts %p.\n", size
, layouts
);
1372 if ((count
= USER_Driver
->pGetKeyboardLayoutList( size
, layouts
)) != ~0) return count
;
1374 layout
= get_locale_kbd_layout();
1378 if (size
&& layouts
)
1380 layouts
[count
- 1] = layout
;
1381 if (count
== size
) return count
;
1384 if (!RegOpenKeyW( HKEY_LOCAL_MACHINE
, L
"System\\CurrentControlSet\\Control\\Keyboard Layouts", &hkey
))
1386 while (!RegEnumKeyW( hkey
, i
++, klid
, ARRAY_SIZE(klid
) ))
1388 tmp
= wcstoul( klid
, NULL
, 16 );
1389 value_size
= sizeof(value
);
1390 if (!RegGetValueW( hkey
, klid
, L
"Layout Id", RRF_RT_REG_SZ
, NULL
, (void *)&value
, &value_size
))
1391 tmp
= MAKELONG( LOWORD( tmp
), 0xf000 | (wcstoul( value
, NULL
, 16 ) & 0xfff) );
1393 if (layout
== UlongToHandle( tmp
)) continue;
1396 if (size
&& layouts
)
1398 layouts
[count
- 1] = UlongToHandle( tmp
);
1399 if (count
== size
) break;
1402 RegCloseKey( hkey
);
1409 /***********************************************************************
1410 * RegisterHotKey (USER32.@)
1412 BOOL WINAPI
RegisterHotKey(HWND hwnd
,INT id
,UINT modifiers
,UINT vk
)
1417 TRACE_(keyboard
)("(%p,%d,0x%08x,%X)\n",hwnd
,id
,modifiers
,vk
);
1419 if ((hwnd
== NULL
|| WIN_IsCurrentThread(hwnd
)) &&
1420 !USER_Driver
->pRegisterHotKey(hwnd
, modifiers
, vk
))
1423 SERVER_START_REQ( register_hotkey
)
1425 req
->window
= wine_server_user_handle( hwnd
);
1427 req
->flags
= modifiers
;
1429 if ((ret
= !wine_server_call_err( req
)))
1431 replaced
= reply
->replaced
;
1432 modifiers
= reply
->flags
;
1438 if (ret
&& replaced
)
1439 USER_Driver
->pUnregisterHotKey(hwnd
, modifiers
, vk
);
1444 /***********************************************************************
1445 * UnregisterHotKey (USER32.@)
1447 BOOL WINAPI
UnregisterHotKey(HWND hwnd
,INT id
)
1452 TRACE_(keyboard
)("(%p,%d)\n",hwnd
,id
);
1454 SERVER_START_REQ( unregister_hotkey
)
1456 req
->window
= wine_server_user_handle( hwnd
);
1458 if ((ret
= !wine_server_call_err( req
)))
1460 modifiers
= reply
->flags
;
1467 USER_Driver
->pUnregisterHotKey(hwnd
, modifiers
, vk
);
1472 /***********************************************************************
1473 * LoadKeyboardLayoutW (USER32.@)
1475 HKL WINAPI
LoadKeyboardLayoutW(LPCWSTR pwszKLID
, UINT Flags
)
1477 TRACE_(keyboard
)("(%s, %d)\n", debugstr_w(pwszKLID
), Flags
);
1479 return USER_Driver
->pLoadKeyboardLayout(pwszKLID
, Flags
);
1482 /***********************************************************************
1483 * LoadKeyboardLayoutA (USER32.@)
1485 HKL WINAPI
LoadKeyboardLayoutA(LPCSTR pwszKLID
, UINT Flags
)
1488 UNICODE_STRING pwszKLIDW
;
1490 if (pwszKLID
) RtlCreateUnicodeStringFromAsciiz(&pwszKLIDW
, pwszKLID
);
1491 else pwszKLIDW
.Buffer
= NULL
;
1493 ret
= LoadKeyboardLayoutW(pwszKLIDW
.Buffer
, Flags
);
1494 RtlFreeUnicodeString(&pwszKLIDW
);
1499 /***********************************************************************
1500 * UnloadKeyboardLayout (USER32.@)
1502 BOOL WINAPI
UnloadKeyboardLayout(HKL hkl
)
1504 TRACE_(keyboard
)("(%p)\n", hkl
);
1506 return USER_Driver
->pUnloadKeyboardLayout(hkl
);
1509 typedef struct __TRACKINGLIST
{
1510 TRACKMOUSEEVENT tme
;
1511 POINT pos
; /* center of hover rectangle */
1514 /* FIXME: move tracking stuff into a per thread data */
1515 static _TRACKINGLIST tracking_info
;
1516 static UINT_PTR timer
;
1518 static void check_mouse_leave(HWND hwnd
, int hittest
)
1520 if (tracking_info
.tme
.hwndTrack
!= hwnd
)
1522 if (tracking_info
.tme
.dwFlags
& TME_NONCLIENT
)
1523 PostMessageW(tracking_info
.tme
.hwndTrack
, WM_NCMOUSELEAVE
, 0, 0);
1525 PostMessageW(tracking_info
.tme
.hwndTrack
, WM_MOUSELEAVE
, 0, 0);
1527 /* remove the TME_LEAVE flag */
1528 tracking_info
.tme
.dwFlags
&= ~TME_LEAVE
;
1532 if (hittest
== HTCLIENT
)
1534 if (tracking_info
.tme
.dwFlags
& TME_NONCLIENT
)
1536 PostMessageW(tracking_info
.tme
.hwndTrack
, WM_NCMOUSELEAVE
, 0, 0);
1537 /* remove the TME_LEAVE flag */
1538 tracking_info
.tme
.dwFlags
&= ~TME_LEAVE
;
1543 if (!(tracking_info
.tme
.dwFlags
& TME_NONCLIENT
))
1545 PostMessageW(tracking_info
.tme
.hwndTrack
, WM_MOUSELEAVE
, 0, 0);
1546 /* remove the TME_LEAVE flag */
1547 tracking_info
.tme
.dwFlags
&= ~TME_LEAVE
;
1553 static void CALLBACK
TrackMouseEventProc(HWND hwnd
, UINT uMsg
, UINT_PTR idEvent
,
1557 INT hoverwidth
= 0, hoverheight
= 0, hittest
;
1559 TRACE("hwnd %p, msg %04x, id %04lx, time %u\n", hwnd
, uMsg
, idEvent
, dwTime
);
1562 hwnd
= WINPOS_WindowFromPoint(hwnd
, pos
, &hittest
);
1564 TRACE("point %s hwnd %p hittest %d\n", wine_dbgstr_point(&pos
), hwnd
, hittest
);
1566 SystemParametersInfoW(SPI_GETMOUSEHOVERWIDTH
, 0, &hoverwidth
, 0);
1567 SystemParametersInfoW(SPI_GETMOUSEHOVERHEIGHT
, 0, &hoverheight
, 0);
1569 TRACE("tracked pos %s, current pos %s, hover width %d, hover height %d\n",
1570 wine_dbgstr_point(&tracking_info
.pos
), wine_dbgstr_point(&pos
),
1571 hoverwidth
, hoverheight
);
1573 /* see if this tracking event is looking for TME_LEAVE and that the */
1574 /* mouse has left the window */
1575 if (tracking_info
.tme
.dwFlags
& TME_LEAVE
)
1577 check_mouse_leave(hwnd
, hittest
);
1580 if (tracking_info
.tme
.hwndTrack
!= hwnd
)
1582 /* mouse is gone, stop tracking mouse hover */
1583 tracking_info
.tme
.dwFlags
&= ~TME_HOVER
;
1586 /* see if we are tracking hovering for this hwnd */
1587 if (tracking_info
.tme
.dwFlags
& TME_HOVER
)
1589 /* has the cursor moved outside the rectangle centered around pos? */
1590 if ((abs(pos
.x
- tracking_info
.pos
.x
) > (hoverwidth
/ 2)) ||
1591 (abs(pos
.y
- tracking_info
.pos
.y
) > (hoverheight
/ 2)))
1593 /* record this new position as the current position */
1594 tracking_info
.pos
= pos
;
1598 if (hittest
== HTCLIENT
)
1600 ScreenToClient(hwnd
, &pos
);
1601 TRACE("client cursor pos %s\n", wine_dbgstr_point(&pos
));
1603 PostMessageW(tracking_info
.tme
.hwndTrack
, WM_MOUSEHOVER
,
1604 get_key_state(), MAKELPARAM( pos
.x
, pos
.y
));
1608 if (tracking_info
.tme
.dwFlags
& TME_NONCLIENT
)
1609 PostMessageW(tracking_info
.tme
.hwndTrack
, WM_NCMOUSEHOVER
,
1610 hittest
, MAKELPARAM( pos
.x
, pos
.y
));
1613 /* stop tracking mouse hover */
1614 tracking_info
.tme
.dwFlags
&= ~TME_HOVER
;
1618 /* stop the timer if the tracking list is empty */
1619 if (!(tracking_info
.tme
.dwFlags
& (TME_HOVER
| TME_LEAVE
)))
1621 KillSystemTimer(tracking_info
.tme
.hwndTrack
, timer
);
1623 tracking_info
.tme
.hwndTrack
= 0;
1624 tracking_info
.tme
.dwFlags
= 0;
1625 tracking_info
.tme
.dwHoverTime
= 0;
1630 /***********************************************************************
1631 * TrackMouseEvent [USER32]
1633 * Requests notification of mouse events
1635 * During mouse tracking WM_MOUSEHOVER or WM_MOUSELEAVE events are posted
1636 * to the hwnd specified in the ptme structure. After the event message
1637 * is posted to the hwnd, the entry in the queue is removed.
1639 * If the current hwnd isn't ptme->hwndTrack the TME_HOVER flag is completely
1640 * ignored. The TME_LEAVE flag results in a WM_MOUSELEAVE message being posted
1641 * immediately and the TME_LEAVE flag being ignored.
1644 * ptme [I,O] pointer to TRACKMOUSEEVENT information structure.
1653 TrackMouseEvent (TRACKMOUSEEVENT
*ptme
)
1660 TRACE("%x, %x, %p, %u\n", ptme
->cbSize
, ptme
->dwFlags
, ptme
->hwndTrack
, ptme
->dwHoverTime
);
1662 if (ptme
->cbSize
!= sizeof(TRACKMOUSEEVENT
)) {
1663 WARN("wrong TRACKMOUSEEVENT size from app\n");
1664 SetLastError(ERROR_INVALID_PARAMETER
);
1668 /* fill the TRACKMOUSEEVENT struct with the current tracking for the given hwnd */
1669 if (ptme
->dwFlags
& TME_QUERY
)
1671 *ptme
= tracking_info
.tme
;
1672 /* set cbSize in the case it's not initialized yet */
1673 ptme
->cbSize
= sizeof(TRACKMOUSEEVENT
);
1675 return TRUE
; /* return here, TME_QUERY is retrieving information */
1678 if (!IsWindow(ptme
->hwndTrack
))
1680 SetLastError(ERROR_INVALID_WINDOW_HANDLE
);
1684 hover_time
= (ptme
->dwFlags
& TME_HOVER
) ? ptme
->dwHoverTime
: HOVER_DEFAULT
;
1686 /* if HOVER_DEFAULT was specified replace this with the system's current value.
1687 * TME_LEAVE doesn't need to specify hover time so use default */
1688 if (hover_time
== HOVER_DEFAULT
|| hover_time
== 0)
1689 SystemParametersInfoW(SPI_GETMOUSEHOVERTIME
, 0, &hover_time
, 0);
1692 hwnd
= WINPOS_WindowFromPoint(ptme
->hwndTrack
, pos
, &hittest
);
1693 TRACE("point %s hwnd %p hittest %d\n", wine_dbgstr_point(&pos
), hwnd
, hittest
);
1695 if (ptme
->dwFlags
& ~(TME_CANCEL
| TME_HOVER
| TME_LEAVE
| TME_NONCLIENT
))
1696 FIXME("Unknown flag(s) %08x\n", ptme
->dwFlags
& ~(TME_CANCEL
| TME_HOVER
| TME_LEAVE
| TME_NONCLIENT
));
1698 if (ptme
->dwFlags
& TME_CANCEL
)
1700 if (tracking_info
.tme
.hwndTrack
== ptme
->hwndTrack
)
1702 tracking_info
.tme
.dwFlags
&= ~(ptme
->dwFlags
& ~TME_CANCEL
);
1704 /* if we aren't tracking on hover or leave remove this entry */
1705 if (!(tracking_info
.tme
.dwFlags
& (TME_HOVER
| TME_LEAVE
)))
1707 KillSystemTimer(tracking_info
.tme
.hwndTrack
, timer
);
1709 tracking_info
.tme
.hwndTrack
= 0;
1710 tracking_info
.tme
.dwFlags
= 0;
1711 tracking_info
.tme
.dwHoverTime
= 0;
1715 /* In our implementation it's possible that another window will receive a
1716 * WM_MOUSEMOVE and call TrackMouseEvent before TrackMouseEventProc is
1717 * called. In such a situation post the WM_MOUSELEAVE now */
1718 if (tracking_info
.tme
.dwFlags
& TME_LEAVE
&& tracking_info
.tme
.hwndTrack
!= NULL
)
1719 check_mouse_leave(hwnd
, hittest
);
1723 KillSystemTimer(tracking_info
.tme
.hwndTrack
, timer
);
1725 tracking_info
.tme
.hwndTrack
= 0;
1726 tracking_info
.tme
.dwFlags
= 0;
1727 tracking_info
.tme
.dwHoverTime
= 0;
1730 if (ptme
->hwndTrack
== hwnd
)
1732 /* Adding new mouse event to the tracking list */
1733 tracking_info
.tme
= *ptme
;
1734 tracking_info
.tme
.dwHoverTime
= hover_time
;
1736 /* Initialize HoverInfo variables even if not hover tracking */
1737 tracking_info
.pos
= pos
;
1739 timer
= SetSystemTimer(tracking_info
.tme
.hwndTrack
, (UINT_PTR
)&tracking_info
.tme
, hover_time
, TrackMouseEventProc
);
1746 /***********************************************************************
1747 * GetMouseMovePointsEx [USER32]
1750 * Success: count of point set in the buffer
1753 int WINAPI
GetMouseMovePointsEx( UINT size
, LPMOUSEMOVEPOINT ptin
, LPMOUSEMOVEPOINT ptout
, int count
, DWORD resolution
)
1755 cursor_pos_t
*pos
, positions
[64];
1760 TRACE( "%d, %p, %p, %d, %d\n", size
, ptin
, ptout
, count
, resolution
);
1762 if ((size
!= sizeof(MOUSEMOVEPOINT
)) || (count
< 0) || (count
> ARRAY_SIZE( positions
)))
1764 SetLastError( ERROR_INVALID_PARAMETER
);
1768 if (!ptin
|| (!ptout
&& count
))
1770 SetLastError( ERROR_NOACCESS
);
1774 if (resolution
!= GMMP_USE_DISPLAY_POINTS
)
1776 FIXME( "only GMMP_USE_DISPLAY_POINTS is supported for now\n" );
1777 SetLastError( ERROR_POINT_NOT_FOUND
);
1781 SERVER_START_REQ( get_cursor_history
)
1783 wine_server_set_reply( req
, &positions
, sizeof(positions
) );
1784 if (wine_server_call_err( req
)) return -1;
1788 for (i
= 0; i
< ARRAY_SIZE( positions
); i
++)
1790 pos
= &positions
[i
];
1791 if (ptin
->x
== pos
->x
&& ptin
->y
== pos
->y
&& (!ptin
->time
|| ptin
->time
== pos
->time
))
1795 if (i
== ARRAY_SIZE( positions
))
1797 SetLastError( ERROR_POINT_NOT_FOUND
);
1801 for (copied
= 0; copied
< count
&& i
< ARRAY_SIZE( positions
); copied
++, i
++)
1803 pos
= &positions
[i
];
1804 ptout
[copied
].x
= pos
->x
;
1805 ptout
[copied
].y
= pos
->y
;
1806 ptout
[copied
].time
= pos
->time
;
1807 ptout
[copied
].dwExtraInfo
= pos
->info
;
1813 /***********************************************************************
1814 * EnableMouseInPointer (USER32.@)
1816 BOOL WINAPI
EnableMouseInPointer(BOOL enable
)
1818 FIXME("(%#x) stub\n", enable
);
1820 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1824 static DWORD CALLBACK
devnotify_window_callback(HANDLE handle
, DWORD flags
, DEV_BROADCAST_HDR
*header
)
1826 SendMessageTimeoutW(handle
, WM_DEVICECHANGE
, flags
, (LPARAM
)header
, SMTO_ABORTIFHUNG
, 2000, NULL
);
1830 static DWORD CALLBACK
devnotify_service_callback(HANDLE handle
, DWORD flags
, DEV_BROADCAST_HDR
*header
)
1832 FIXME("Support for service handles is not yet implemented!\n");
1836 struct device_notification_details
1838 DWORD (CALLBACK
*cb
)(HANDLE handle
, DWORD flags
, DEV_BROADCAST_HDR
*header
);
1842 extern HDEVNOTIFY WINAPI
I_ScRegisterDeviceNotification( struct device_notification_details
*details
,
1843 void *filter
, DWORD flags
);
1844 extern BOOL WINAPI
I_ScUnregisterDeviceNotification( HDEVNOTIFY handle
);
1846 /***********************************************************************
1847 * RegisterDeviceNotificationA (USER32.@)
1849 * See RegisterDeviceNotificationW.
1851 HDEVNOTIFY WINAPI
RegisterDeviceNotificationA(HANDLE hRecipient
, LPVOID pNotificationFilter
, DWORD dwFlags
)
1853 TRACE("(hwnd=%p, filter=%p,flags=0x%08x)\n",
1854 hRecipient
,pNotificationFilter
,dwFlags
);
1855 if (pNotificationFilter
)
1856 FIXME("The notification filter will requires an A->W when filter support is implemented\n");
1857 return RegisterDeviceNotificationW(hRecipient
, pNotificationFilter
, dwFlags
);
1860 /***********************************************************************
1861 * RegisterDeviceNotificationW (USER32.@)
1863 HDEVNOTIFY WINAPI
RegisterDeviceNotificationW( HANDLE handle
, void *filter
, DWORD flags
)
1865 struct device_notification_details details
;
1867 TRACE("handle %p, filter %p, flags %#x\n", handle
, filter
, flags
);
1869 if (flags
& ~(DEVICE_NOTIFY_SERVICE_HANDLE
| DEVICE_NOTIFY_ALL_INTERFACE_CLASSES
))
1870 FIXME("unhandled flags %#x\n", flags
);
1872 details
.handle
= handle
;
1874 if (flags
& DEVICE_NOTIFY_SERVICE_HANDLE
)
1875 details
.cb
= devnotify_service_callback
;
1877 details
.cb
= devnotify_window_callback
;
1879 return I_ScRegisterDeviceNotification( &details
, filter
, 0 );
1882 /***********************************************************************
1883 * UnregisterDeviceNotification (USER32.@)
1885 BOOL WINAPI
UnregisterDeviceNotification( HDEVNOTIFY handle
)
1887 TRACE("%p\n", handle
);
1889 return I_ScUnregisterDeviceNotification( handle
);