mf/evr: Post sink marker events.
[wine.git] / dlls / user32 / input.c
blobbebdc3e012ba533954c3f98120ef5b1512198979
1 /*
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
25 #include <stdlib.h>
26 #include <string.h>
27 #include <stdarg.h>
28 #include <stdio.h>
29 #include <ctype.h>
30 #include <assert.h>
32 #define NONAMELESSUNION
34 #include "ntstatus.h"
35 #define WIN32_NO_STATUS
36 #include "windef.h"
37 #include "winbase.h"
38 #include "wingdi.h"
39 #include "winuser.h"
40 #include "winnls.h"
41 #include "winternl.h"
42 #include "winerror.h"
43 #include "win.h"
44 #include "user_private.h"
45 #include "dbt.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 /***********************************************************************
55 * get_key_state
57 static WORD get_key_state(void)
59 WORD ret = 0;
61 if (GetSystemMetrics( SM_SWAPBUTTON ))
63 if (GetAsyncKeyState(VK_RBUTTON) & 0x80) ret |= MK_LBUTTON;
64 if (GetAsyncKeyState(VK_LBUTTON) & 0x80) ret |= MK_RBUTTON;
66 else
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;
76 return ret;
80 /***********************************************************************
81 * get_locale_kbd_layout
83 static HKL get_locale_kbd_layout(void)
85 ULONG_PTR layout;
86 LANGID langid;
88 /* FIXME:
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 */
110 else
111 layout = MAKELONG( layout, layout );
113 return (HKL)layout;
117 /**********************************************************************
118 * set_capture_window
120 BOOL set_capture_window( HWND hwnd, UINT gui_flags, HWND *prev_ret )
122 HWND previous = 0;
123 UINT flags = 0;
124 BOOL 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 );
132 req->flags = flags;
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 );
139 SERVER_END_REQ;
141 if (ret)
143 USER_Driver->pSetCapture( hwnd, gui_flags );
145 if (previous)
146 SendMessageW( previous, WM_CAPTURECHANGED, 0, (LPARAM)hwnd );
148 if (prev_ret) *prev_ret = previous;
150 return ret;
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) );
163 return !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);
185 else
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 );
192 else
194 int accel[3];
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])
203 input->u.mi.dx *= 2;
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])
208 input->u.mi.dy *= 2;
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 )
219 UINT i;
220 NTSTATUS status = STATUS_SUCCESS;
222 if (size != sizeof(INPUT))
224 SetLastError( ERROR_INVALID_PARAMETER );
225 return 0;
228 if (!count)
230 SetLastError( ERROR_INVALID_PARAMETER );
231 return 0;
234 if (!inputs)
236 SetLastError( ERROR_NOACCESS );
237 return 0;
240 for (i = 0; i < count; i++)
242 INPUT input = inputs[i];
243 switch (input.type)
245 case INPUT_MOUSE:
246 /* we need to update the coordinates to what the server expects */
247 update_mouse_coords( &input );
248 /* fallthrough */
249 case INPUT_KEYBOARD:
250 status = send_hardware_message( 0, &input, NULL, SEND_HWMSG_INJECTED );
251 break;
252 case INPUT_HARDWARE:
253 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
254 return 0;
257 if (status)
259 SetLastError( RtlNtStatusToDosError(status) );
260 break;
264 return i;
268 /***********************************************************************
269 * keybd_event (USER32.@)
271 void WINAPI keybd_event( BYTE bVk, BYTE bScan,
272 DWORD dwFlags, ULONG_PTR dwExtraInfo )
274 INPUT input;
276 input.type = INPUT_KEYBOARD;
277 input.u.ki.wVk = bVk;
278 input.u.ki.wScan = bScan;
279 input.u.ki.dwFlags = dwFlags;
280 input.u.ki.time = 0;
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 )
292 INPUT input;
294 input.type = INPUT_MOUSE;
295 input.u.mi.dx = dx;
296 input.u.mi.dy = dy;
297 input.u.mi.mouseData = dwData;
298 input.u.mi.dwFlags = dwFlags;
299 input.u.mi.time = 0;
300 input.u.mi.dwExtraInfo = dwExtraInfo;
301 SendInput( 1, &input, sizeof(input) );
305 /***********************************************************************
306 * GetCursorPos (USER32.@)
308 BOOL WINAPI DECLSPEC_HOTPATCH GetCursorPos( POINT *pt )
310 BOOL ret;
311 DWORD last_change;
312 UINT dpi;
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;
325 SERVER_END_REQ;
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 );
336 return ret;
340 /***********************************************************************
341 * GetCursorInfo (USER32.@)
343 BOOL WINAPI GetCursorInfo( PCURSORINFO pci )
345 BOOL ret;
347 if (!pci) return FALSE;
349 SERVER_START_REQ( get_thread_input )
351 req->tid = 0;
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;
358 SERVER_END_REQ;
359 GetCursorPos(&pci->ptScreenPos);
360 return ret;
364 /***********************************************************************
365 * SetCursorPos (USER32.@)
367 BOOL WINAPI DECLSPEC_HOTPATCH SetCursorPos( INT x, INT y )
369 POINT pt = { x, y };
370 BOOL ret;
371 INT prev_x, prev_y, new_x, new_y;
372 UINT dpi;
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;
380 req->x = pt.x;
381 req->y = pt.y;
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;
390 SERVER_END_REQ;
391 if (ret && (prev_x != new_x || prev_y != new_y)) USER_Driver->pSetCursorPos( new_x, new_y );
392 return ret;
395 /**********************************************************************
396 * SetCapture (USER32.@)
398 HWND WINAPI DECLSPEC_HOTPATCH SetCapture( HWND hwnd )
400 HWND previous = 0;
402 set_capture_window( hwnd, 0, &previous );
403 return 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 );
417 return ret;
421 /**********************************************************************
422 * GetCapture (USER32.@)
424 HWND WINAPI GetCapture(void)
426 HWND ret = 0;
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 );
433 SERVER_END_REQ;
434 return ret;
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
449 * been pressed.
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;
455 BYTE prev_key_state;
456 SHORT ret;
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 */
466 return 0;
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;
474 ret = 0;
475 SERVER_START_REQ( get_key_state )
477 req->async = 1;
478 req->key = key;
479 if (key_state_info)
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;
488 if (key_state_info)
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;
501 SERVER_END_REQ;
503 return ret;
507 /***********************************************************************
508 * GetQueueStatus (USER32.@)
510 DWORD WINAPI GetQueueStatus( UINT flags )
512 DWORD ret;
514 if (flags & ~(QS_ALLINPUT | QS_ALLPOSTMESSAGE | QS_SMRESULT))
516 SetLastError( ERROR_INVALID_FLAGS );
517 return 0;
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 );
528 SERVER_END_REQ;
529 return ret;
533 /***********************************************************************
534 * GetInputState (USER32.@)
536 BOOL WINAPI GetInputState(void)
538 DWORD ret;
540 check_for_events( QS_INPUT );
542 SERVER_START_REQ( get_queue_status )
544 req->clear_bits = 0;
545 wine_server_call( req );
546 ret = reply->wake_bits & (QS_KEY | QS_MOUSEBUTTON);
548 SERVER_END_REQ;
549 return ret;
553 /******************************************************************
554 * GetLastInputInfo (USER32.@)
556 BOOL WINAPI GetLastInputInfo(PLASTINPUTINFO plii)
558 BOOL ret;
560 TRACE("%p\n", plii);
562 if (plii->cbSize != sizeof (*plii) )
564 SetLastError(ERROR_INVALID_PARAMETER);
565 return FALSE;
568 SERVER_START_REQ( get_last_input_time )
570 ret = !wine_server_call_err( req );
571 if (ret)
572 plii->dwTime = reply->time;
574 SERVER_END_REQ;
575 return ret;
579 /**********************************************************************
580 * AttachThreadInput (USER32.@)
582 * Attaches the input processing mechanism of one thread to that of
583 * another thread.
585 BOOL WINAPI AttachThreadInput( DWORD from, DWORD to, BOOL attach )
587 BOOL ret;
589 SERVER_START_REQ( attach_thread_input )
591 req->tid_from = from;
592 req->tid_to = to;
593 req->attach = attach;
594 ret = !wine_server_call_err( req );
596 SERVER_END_REQ;
597 return ret;
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)
610 SHORT retval = 0;
612 SERVER_START_REQ( get_key_state )
614 req->key = vkey;
615 if (!wine_server_call( req )) retval = (signed char)(reply->state & 0x81);
617 SERVER_END_REQ;
618 TRACE("key (0x%x) -> %x\n", vkey, retval);
619 return retval;
623 /**********************************************************************
624 * GetKeyboardState (USER32.@)
626 BOOL WINAPI DECLSPEC_HOTPATCH GetKeyboardState( LPBYTE state )
628 BOOL ret;
629 UINT i;
631 TRACE("(%p)\n", state);
633 memset( state, 0, 256 );
634 SERVER_START_REQ( get_key_state )
636 req->key = -1;
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;
641 SERVER_END_REQ;
642 return ret;
646 /**********************************************************************
647 * SetKeyboardState (USER32.@)
649 BOOL WINAPI SetKeyboardState( LPBYTE state )
651 BOOL ret;
653 SERVER_START_REQ( set_key_state )
655 wine_server_add_data( req, state, 256 );
656 ret = !wine_server_call_err( req );
658 SERVER_END_REQ;
659 return ret;
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 :
669 * 0 Unshifted
670 * 1 Shift
671 * 2 Ctrl
672 * 3-5 Shift-key combinations that are not used for characters
673 * 6 Ctrl-Alt
674 * 7 Ctrl-Alt-Shift
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)
682 WCHAR wChar;
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)
703 WCHAR wChar;
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;
717 SHORT ret;
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;
770 else ret = -1;
772 TRACE_(keyboard)( "ret %04x\n", ret );
773 return ret;
776 /**********************************************************************
777 * OemKeyScan (USER32.@)
779 DWORD WINAPI OemKeyScan( WORD oem )
781 WCHAR wchr;
782 DWORD vkey, scan;
783 char oem_char = LOBYTE( oem );
785 if (!OemToCharBuffW( &oem_char, &wchr, 1 ))
786 return -1;
788 vkey = VkKeyScanW( wchr );
789 scan = MapVirtualKeyW( LOBYTE( vkey ), MAPVK_VK_TO_VSC );
790 if (!scan) return -1;
792 vkey &= 0xff00;
793 vkey <<= 8;
794 return vkey | scan;
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;
808 switch(nTypeFlag)
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 */
817 else
818 return 0; /* AT-101 */
819 case 2: /* Number of F-keys */
820 return 12; /* It has 12 F-keys */
823 else
825 switch(nTypeFlag)
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)
860 UINT ret;
862 ret = MapVirtualKeyExW( code, maptype, hkl );
863 if (maptype == MAPVK_VK_TO_CHAR)
865 BYTE ch = 0;
866 WCHAR wch = ret;
868 WideCharToMultiByte( CP_ACP, 0, &wch, 1, (LPSTR)&ch, 1, NULL, NULL );
869 ret = ch;
871 return ret;
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,
894 /* 0xe000 */
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,
911 /* 0xe100 */
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,
968 /* extended */
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;
995 UINT ret;
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);
1008 switch (type)
1010 case MAPVK_VK_TO_VSC_EX:
1011 case MAPVK_VK_TO_VSC:
1012 switch (code)
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;
1036 else ret &= 0xff;
1038 else if (ret >= 0x100) ret += 0xdf00;
1039 break;
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)
1048 switch (ret)
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;
1055 break;
1056 case MAPVK_VK_TO_CHAR:
1057 if (code >= vk2char_size) ret = 0;
1058 else ret = vk2char[code];
1059 break;
1060 default:
1061 FIXME_(keyboard)( "unknown type %d\n", type );
1062 return 0;
1065 TRACE_(keyboard)( "returning 0x%04x\n", ret );
1066 return ret;
1069 /****************************************************************************
1070 * GetKBCodePage (USER32.@)
1072 UINT WINAPI GetKBCodePage(void)
1074 return GetOEMCP();
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();
1093 return 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;
1105 return FALSE;
1108 /****************************************************************************
1109 * GetKeyboardLayoutNameW (USER32.@)
1111 BOOL WINAPI GetKeyboardLayoutNameW(LPWSTR pwszKLID)
1113 if (!pwszKLID)
1115 SetLastError(ERROR_NOACCESS);
1116 return FALSE;
1118 return USER_Driver->pGetKeyboardLayoutName(pwszKLID);
1121 /****************************************************************************
1122 * GetKeyNameTextA (USER32.@)
1124 INT WINAPI GetKeyNameTextA(LONG lParam, LPSTR lpBuffer, INT nSize)
1126 WCHAR buf[256];
1127 INT ret;
1129 if (!nSize || !GetKeyNameTextW(lParam, buf, 256))
1131 lpBuffer[0] = 0;
1132 return 0;
1134 ret = WideCharToMultiByte(CP_ACP, 0, buf, -1, lpBuffer, nSize, NULL, NULL);
1135 if (!ret && nSize)
1137 ret = nSize - 1;
1138 lpBuffer[ret] = 0;
1140 else ret--;
1142 return ret;
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;
1153 const UINT *vsc2vk;
1154 WCHAR tmp[2];
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]))
1172 case VK_RSHIFT:
1173 case VK_RCONTROL:
1174 case VK_RMENU:
1175 for (code = 0; code < vsc2vk_size; ++code)
1176 if (vsc2vk[code] == (vkey - 1)) break;
1177 break;
1181 if (code >= vscname_size) buffer[0] = 0;
1182 else if (vscname[code]) lstrcpynW( buffer, vscname[code], size );
1183 else
1185 vkey = MapVirtualKeyW( code & 0xff, MAPVK_VSC_TO_VK );
1186 tmp[0] = MapVirtualKeyW( vkey, MAPVK_VK_TO_CHAR );
1187 tmp[1] = 0;
1188 lstrcpynW( buffer, tmp, size );
1190 len = wcslen( buffer );
1192 TRACE_(keyboard)( "ret %d, str %s.\n", len, debugstr_w(buffer) );
1193 return len;
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;
1212 WCHAR buffer[2];
1213 INT len;
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;
1230 else if (!ctrl)
1232 switch (virt)
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;
1253 default:
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)
1261 buffer[0] = '.';
1262 else
1263 buffer[0] = 0;
1264 break;
1267 else if (!alt) /* Control codes */
1269 switch (virt)
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;
1277 default:
1278 if (virt >= 'A' && virt <= 'Z') buffer[0] = virt - 'A' + 1;
1279 else buffer[0] = 0;
1280 break;
1283 else buffer[0] = 0;
1284 buffer[1] = 0;
1285 len = wcslen( buffer );
1286 lstrcpynW( str, buffer, size );
1288 TRACE_(keyboard)( "ret %d, str %s.\n", len, debugstr_w(str) );
1289 return len;
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 )
1307 WCHAR uni_chars[2];
1308 INT ret, n_ret;
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 */
1312 else n_ret = ret;
1313 WideCharToMultiByte(CP_ACP, 0, uni_chars, n_ret, (LPSTR)lpChar, 2, NULL, NULL);
1314 return ret;
1317 /**********************************************************************
1318 * ActivateKeyboardLayout (USER32.@)
1320 HKL WINAPI ActivateKeyboardLayout( HKL layout, UINT flags )
1322 struct user_thread_info *info = get_user_thread_info();
1323 HKL old_layout;
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" );
1333 return 0;
1336 if (!USER_Driver->pActivateKeyboardLayout( layout, flags ))
1337 return 0;
1339 old_layout = info->kbd_layout;
1340 info->kbd_layout = layout;
1342 if (!old_layout) return get_locale_kbd_layout();
1343 return old_layout;
1346 /**********************************************************************
1347 * BlockInput (USER32.@)
1349 BOOL WINAPI BlockInput(BOOL fBlockIt)
1351 FIXME_(keyboard)("(%d): stub\n", fBlockIt);
1352 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1354 return FALSE;
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;
1367 HKEY hkey;
1368 HKL layout;
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();
1375 count = 0;
1377 count++;
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;
1395 count++;
1396 if (size && layouts)
1398 layouts[count - 1] = UlongToHandle( tmp );
1399 if (count == size) break;
1402 RegCloseKey( hkey );
1405 return count;
1409 /***********************************************************************
1410 * RegisterHotKey (USER32.@)
1412 BOOL WINAPI RegisterHotKey(HWND hwnd,INT id,UINT modifiers,UINT vk)
1414 BOOL ret;
1415 int replaced=0;
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))
1421 return FALSE;
1423 SERVER_START_REQ( register_hotkey )
1425 req->window = wine_server_user_handle( hwnd );
1426 req->id = id;
1427 req->flags = modifiers;
1428 req->vkey = vk;
1429 if ((ret = !wine_server_call_err( req )))
1431 replaced = reply->replaced;
1432 modifiers = reply->flags;
1433 vk = reply->vkey;
1436 SERVER_END_REQ;
1438 if (ret && replaced)
1439 USER_Driver->pUnregisterHotKey(hwnd, modifiers, vk);
1441 return ret;
1444 /***********************************************************************
1445 * UnregisterHotKey (USER32.@)
1447 BOOL WINAPI UnregisterHotKey(HWND hwnd,INT id)
1449 BOOL ret;
1450 UINT modifiers, vk;
1452 TRACE_(keyboard)("(%p,%d)\n",hwnd,id);
1454 SERVER_START_REQ( unregister_hotkey )
1456 req->window = wine_server_user_handle( hwnd );
1457 req->id = id;
1458 if ((ret = !wine_server_call_err( req )))
1460 modifiers = reply->flags;
1461 vk = reply->vkey;
1464 SERVER_END_REQ;
1466 if (ret)
1467 USER_Driver->pUnregisterHotKey(hwnd, modifiers, vk);
1469 return ret;
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)
1487 HKL ret;
1488 UNICODE_STRING pwszKLIDW;
1490 if (pwszKLID) RtlCreateUnicodeStringFromAsciiz(&pwszKLIDW, pwszKLID);
1491 else pwszKLIDW.Buffer = NULL;
1493 ret = LoadKeyboardLayoutW(pwszKLIDW.Buffer, Flags);
1494 RtlFreeUnicodeString(&pwszKLIDW);
1495 return ret;
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 */
1512 } _TRACKINGLIST;
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);
1524 else
1525 PostMessageW(tracking_info.tme.hwndTrack, WM_MOUSELEAVE, 0, 0);
1527 /* remove the TME_LEAVE flag */
1528 tracking_info.tme.dwFlags &= ~TME_LEAVE;
1530 else
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;
1541 else
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,
1554 DWORD dwTime)
1556 POINT pos;
1557 INT hoverwidth = 0, hoverheight = 0, hittest;
1559 TRACE("hwnd %p, msg %04x, id %04lx, time %u\n", hwnd, uMsg, idEvent, dwTime);
1561 GetCursorPos(&pos);
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;
1596 else
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 ));
1606 else
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);
1622 timer = 0;
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.
1643 * PARAMS
1644 * ptme [I,O] pointer to TRACKMOUSEEVENT information structure.
1646 * RETURNS
1647 * Success: non-zero
1648 * Failure: zero
1652 BOOL WINAPI
1653 TrackMouseEvent (TRACKMOUSEEVENT *ptme)
1655 HWND hwnd;
1656 POINT pos;
1657 DWORD hover_time;
1658 INT hittest;
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);
1665 return FALSE;
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);
1681 return FALSE;
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);
1691 GetCursorPos(&pos);
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);
1708 timer = 0;
1709 tracking_info.tme.hwndTrack = 0;
1710 tracking_info.tme.dwFlags = 0;
1711 tracking_info.tme.dwHoverTime = 0;
1714 } else {
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);
1721 if (timer)
1723 KillSystemTimer(tracking_info.tme.hwndTrack, timer);
1724 timer = 0;
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);
1743 return TRUE;
1746 /***********************************************************************
1747 * GetMouseMovePointsEx [USER32]
1749 * RETURNS
1750 * Success: count of point set in the buffer
1751 * Failure: -1
1753 int WINAPI GetMouseMovePointsEx( UINT size, LPMOUSEMOVEPOINT ptin, LPMOUSEMOVEPOINT ptout, int count, DWORD resolution )
1755 cursor_pos_t *pos, positions[64];
1756 int copied;
1757 unsigned int i;
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 );
1765 return -1;
1768 if (!ptin || (!ptout && count))
1770 SetLastError( ERROR_NOACCESS );
1771 return -1;
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 );
1778 return -1;
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;
1786 SERVER_END_REQ;
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))
1792 break;
1795 if (i == ARRAY_SIZE( positions ))
1797 SetLastError( ERROR_POINT_NOT_FOUND );
1798 return -1;
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;
1810 return copied;
1813 /***********************************************************************
1814 * EnableMouseInPointer (USER32.@)
1816 BOOL WINAPI EnableMouseInPointer(BOOL enable)
1818 FIXME("(%#x) stub\n", enable);
1820 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1821 return FALSE;
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);
1827 return 0;
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");
1833 return 0;
1836 struct device_notification_details
1838 DWORD (CALLBACK *cb)(HANDLE handle, DWORD flags, DEV_BROADCAST_HDR *header);
1839 HANDLE handle;
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;
1876 else
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 );