3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * PROJECT: ReactOS user32.dll
22 * FILE: lib/user32/windows/input.c
24 * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
26 * 09-05-2001 CSH Created
29 /* INCLUDES ******************************************************************/
33 #include <wine/debug.h>
34 WINE_DEFAULT_DEBUG_CHANNEL(user32
);
36 /* GLOBALS *******************************************************************/
40 /* FUNCTIONS *****************************************************************/
53 return NtUserDragDetect(hWnd
, pt
);
58 ULONG dx
= GetSystemMetrics(SM_CXDRAG
);
59 ULONG dy
= GetSystemMetrics(SM_CYDRAG
);
61 rect
.left
= pt
.x
- dx
;
62 rect
.right
= pt
.x
+ dx
;
64 rect
.bottom
= pt
.y
+ dy
;
71 PeekMessageW(&msg
, 0, WM_MOUSEFIRST
, WM_MOUSELAST
, PM_REMOVE
) ||
72 PeekMessageW(&msg
, 0, WM_KEYFIRST
, WM_KEYLAST
, PM_REMOVE
)
75 if (msg
.message
== WM_LBUTTONUP
)
80 if (msg
.message
== WM_MOUSEMOVE
)
82 tmp
.x
= LOWORD(msg
.lParam
);
83 tmp
.y
= HIWORD(msg
.lParam
);
84 if (!PtInRect(&rect
, tmp
))
90 if (msg
.message
== WM_KEYDOWN
)
92 if (msg
.wParam
== VK_ESCAPE
)
110 BlockInput(BOOL fBlockIt
)
112 return NtUserBlockInput(fBlockIt
);
120 EnableWindow(HWND hWnd
,
123 LONG Style
= GetWindowLongW(hWnd
, GWL_STYLE
);
124 /* check if updating is needed */
125 UINT bIsDisabled
= (Style
& WS_DISABLED
);
126 if ( (bIsDisabled
&& bEnable
) || (!bIsDisabled
&& !bEnable
) )
130 Style
&= ~WS_DISABLED
;
134 Style
|= WS_DISABLED
;
135 /* Remove keyboard focus from that window if it had focus */
136 if (hWnd
== GetFocus())
141 NtUserSetWindowLong(hWnd
, GWL_STYLE
, Style
, FALSE
);
143 SendMessageA(hWnd
, WM_ENABLE
, (LPARAM
) IsWindowEnabled(hWnd
), 0);
145 // Return nonzero if it was disabled, or zero if it wasn't:
146 return IsWindowEnabled(hWnd
);
154 GetAsyncKeyState(int vKey
)
156 if (vKey
< 0 || vKey
> 256)
158 return (SHORT
) NtUserGetAsyncKeyState((DWORD
) vKey
);
167 GetDoubleClickTime(VOID
)
169 return NtUserGetDoubleClickTime();
177 GetKeyboardLayout(DWORD idThread
)
179 return (HKL
)NtUserCallOneParam((DWORD
) idThread
, ONEPARAM_ROUTINE_GETKEYBOARDLAYOUT
);
197 GetKeyNameTextA(LONG lParam
,
201 LPWSTR intermediateString
=
202 HeapAlloc(GetProcessHeap(),0,nSize
* sizeof(WCHAR
));
205 BOOL defChar
= FALSE
;
207 if( !intermediateString
) return 0;
208 ret
= GetKeyNameTextW(lParam
,intermediateString
,nSize
);
209 if( ret
== 0 ) { lpString
[0] = 0; return 0; }
211 wstrLen
= wcslen( intermediateString
);
212 ret
= WideCharToMultiByte(CP_ACP
, 0,
213 intermediateString
, wstrLen
,
214 lpString
, nSize
, ".", &defChar
);
216 HeapFree(GetProcessHeap(),0,intermediateString
);
225 GetKeyNameTextW(LONG lParam
,
229 return NtUserGetKeyNameText( lParam
, lpString
, nSize
);
237 GetKeyState(int nVirtKey
)
239 return (SHORT
) NtUserGetKeyState((DWORD
) nVirtKey
);
247 GetKeyboardLayoutNameA(LPSTR pwszKLID
)
249 WCHAR buf
[KL_NAMELENGTH
];
251 if (GetKeyboardLayoutNameW(buf
))
252 return WideCharToMultiByte( CP_ACP
, 0, buf
, -1, pwszKLID
, KL_NAMELENGTH
, NULL
, NULL
) != 0;
261 GetKeyboardLayoutNameW(LPWSTR pwszKLID
)
263 return NtUserGetKeyboardLayoutName( pwszKLID
);
271 GetKeyboardState(PBYTE lpKeyState
)
274 return (BOOL
) NtUserGetKeyboardState((LPBYTE
) lpKeyState
);
282 GetKeyboardType(int nTypeFlag
)
284 return (int)NtUserCallOneParam((DWORD
) nTypeFlag
, ONEPARAM_ROUTINE_GETKEYBOARDTYPE
);
292 GetLastInputInfo(PLASTINPUTINFO plii
)
294 return NtUserGetLastInputInfo(plii
);
302 LoadKeyboardLayoutA(LPCSTR pwszKLID
,
305 return NtUserLoadKeyboardLayoutEx( NULL
, 0, NULL
, NULL
, NULL
,
306 strtoul(pwszKLID
, NULL
, 16),
315 LoadKeyboardLayoutW(LPCWSTR pwszKLID
,
318 // Look at revision 25596 to see how it's done in windows.
319 // We will do things our own way. Also be compatible too!
320 return NtUserLoadKeyboardLayoutEx( NULL
, 0, NULL
, NULL
, NULL
,
321 wcstoul(pwszKLID
, NULL
, 16),
330 MapVirtualKeyA(UINT uCode
,
333 return MapVirtualKeyExA( uCode
, uMapType
, GetKeyboardLayout( 0 ) );
341 MapVirtualKeyExA(UINT uCode
,
345 return MapVirtualKeyExW( uCode
, uMapType
, dwhkl
);
353 MapVirtualKeyExW(UINT uCode
,
357 return NtUserMapVirtualKeyEx( uCode
, uMapType
, 0, dwhkl
);
365 MapVirtualKeyW(UINT uCode
,
368 return MapVirtualKeyExW( uCode
, uMapType
, GetKeyboardLayout( 0 ) );
376 OemKeyScan(WORD wOemChar
)
382 MultiByteToWideChar(CP_OEMCP
, 0, (PCSTR
)&wOemChar
, 1, &p
, 1);
384 Scan
= MapVirtualKeyW((Vk
& 0x00ff), 0);
387 Page 450-1, MS W2k SuperBible by SAMS. Return, low word has the
388 scan code and high word has the shift state.
390 return ((Vk
& 0xff00) << 8) | Scan
;
398 RegisterHotKey(HWND hWnd
,
403 return (BOOL
)NtUserRegisterHotKey(hWnd
,
414 SetDoubleClickTime(UINT uInterval
)
416 return (BOOL
)NtUserSystemParametersInfo(SPI_SETDOUBLECLICKTIME
,
429 return NtUserSetFocus(hWnd
);
437 SetKeyboardState(LPBYTE lpKeyState
)
439 return (BOOL
) NtUserSetKeyboardState((LPBYTE
)lpKeyState
);
451 return NtUserSwapMouseButton(fSwap
);
459 ToAscii(UINT uVirtKey
,
461 CONST PBYTE lpKeyState
,
465 return ToAsciiEx(uVirtKey
, uScanCode
, lpKeyState
, lpChar
, uFlags
, 0);
473 ToAsciiEx(UINT uVirtKey
,
475 CONST PBYTE lpKeyState
,
483 Ret
= ToUnicodeEx(uVirtKey
, uScanCode
, lpKeyState
, UniChars
, 2, uFlags
, dwhkl
);
484 CharCount
= (Ret
< 0 ? 1 : Ret
);
485 WideCharToMultiByte(CP_ACP
, 0, UniChars
, CharCount
, (LPSTR
) lpChar
, 2, NULL
, NULL
);
495 ToUnicode(UINT wVirtKey
,
497 CONST PBYTE lpKeyState
,
502 return ToUnicodeEx( wVirtKey
, wScanCode
, lpKeyState
, pwszBuff
, cchBuff
,
511 ToUnicodeEx(UINT wVirtKey
,
513 CONST PBYTE lpKeyState
,
519 return NtUserToUnicodeEx( wVirtKey
, wScanCode
, lpKeyState
, pwszBuff
, cchBuff
,
533 if (IsDBCSLeadByte(ch
)) return -1;
535 MultiByteToWideChar(CP_ACP
, 0, &ch
, 1, &wChar
, 1);
536 return VkKeyScanW(wChar
);
544 VkKeyScanExA(CHAR ch
,
549 if (IsDBCSLeadByte(ch
)) return -1;
551 MultiByteToWideChar(CP_ACP
, 0, &ch
, 1, &wChar
, 1);
552 return VkKeyScanExW(wChar
, dwhkl
);
560 VkKeyScanExW(WCHAR ch
,
563 return (SHORT
) NtUserVkKeyScanEx(ch
, dwhkl
, 0);
573 return VkKeyScanExW(ch
, GetKeyboardLayout(0));
587 return NtUserSendInput(nInputs
, pInputs
, cbSize
);
600 ULONG_PTR dwExtraInfo
)
606 Input
.type
= INPUT_KEYBOARD
;
608 Input
.ki
.wScan
= bScan
;
609 Input
.ki
.dwFlags
= dwFlags
;
611 Input
.ki
.dwExtraInfo
= dwExtraInfo
;
613 NtUserSendInput(1, &Input
, sizeof(INPUT
));
627 ULONG_PTR dwExtraInfo
)
631 Input
.type
= INPUT_MOUSE
;
634 Input
.mi
.mouseData
= dwData
;
635 Input
.mi
.dwFlags
= dwFlags
;
637 Input
.mi
.dwExtraInfo
= dwExtraInfo
;
639 NtUserSendInput(1, &Input
, sizeof(INPUT
));
643 /***********************************************************************
646 static WORD
get_key_state(void)
650 if (GetSystemMetrics( SM_SWAPBUTTON
))
652 if (GetAsyncKeyState(VK_RBUTTON
) & 0x80) ret
|= MK_LBUTTON
;
653 if (GetAsyncKeyState(VK_LBUTTON
) & 0x80) ret
|= MK_RBUTTON
;
657 if (GetAsyncKeyState(VK_LBUTTON
) & 0x80) ret
|= MK_LBUTTON
;
658 if (GetAsyncKeyState(VK_RBUTTON
) & 0x80) ret
|= MK_RBUTTON
;
660 if (GetAsyncKeyState(VK_MBUTTON
) & 0x80) ret
|= MK_MBUTTON
;
661 if (GetAsyncKeyState(VK_SHIFT
) & 0x80) ret
|= MK_SHIFT
;
662 if (GetAsyncKeyState(VK_CONTROL
) & 0x80) ret
|= MK_CONTROL
;
663 if (GetAsyncKeyState(VK_XBUTTON1
) & 0x80) ret
|= MK_XBUTTON1
;
664 if (GetAsyncKeyState(VK_XBUTTON2
) & 0x80) ret
|= MK_XBUTTON2
;
668 static void CALLBACK
TrackMouseEventProc(HWND hwndUnused
, UINT uMsg
, UINT_PTR idEvent
,
674 INT hoverwidth
= 0, hoverheight
= 0;
676 PUSER32_TRACKINGLIST ptracking_info
;
678 ptracking_info
= & User32GetThreadData()->tracking_info
;
681 hwnd
= WindowFromPoint(pos
);
683 SystemParametersInfoW(SPI_GETMOUSEHOVERWIDTH
, 0, &hoverwidth
, 0);
684 SystemParametersInfoW(SPI_GETMOUSEHOVERHEIGHT
, 0, &hoverheight
, 0);
686 /* see if this tracking event is looking for TME_LEAVE and that the */
687 /* mouse has left the window */
688 if (ptracking_info
->tme
.dwFlags
& TME_LEAVE
)
690 if (ptracking_info
->tme
.hwndTrack
!= hwnd
)
692 if (ptracking_info
->tme
.dwFlags
& TME_NONCLIENT
)
694 PostMessageW(ptracking_info
->tme
.hwndTrack
, WM_NCMOUSELEAVE
, 0, 0);
698 PostMessageW(ptracking_info
->tme
.hwndTrack
, WM_MOUSELEAVE
, 0, 0);
701 /* remove the TME_LEAVE flag */
702 ptracking_info
->tme
.dwFlags
&= ~TME_LEAVE
;
706 GetClientRect(hwnd
, &client
);
707 MapWindowPoints(hwnd
, NULL
, (LPPOINT
)&client
, 2);
708 if (PtInRect(&client
, pos
))
710 if (ptracking_info
->tme
.dwFlags
& TME_NONCLIENT
)
712 PostMessageW(ptracking_info
->tme
.hwndTrack
, WM_NCMOUSELEAVE
, 0, 0);
713 /* remove the TME_LEAVE flag */
714 ptracking_info
->tme
.dwFlags
&= ~TME_LEAVE
;
719 if (!(ptracking_info
->tme
.dwFlags
& TME_NONCLIENT
))
721 PostMessageW(ptracking_info
->tme
.hwndTrack
, WM_MOUSELEAVE
, 0, 0);
722 /* remove the TME_LEAVE flag */
723 ptracking_info
->tme
.dwFlags
&= ~TME_LEAVE
;
729 /* see if we are tracking hovering for this hwnd */
730 if (ptracking_info
->tme
.dwFlags
& TME_HOVER
)
732 /* has the cursor moved outside the rectangle centered around pos? */
733 if ((abs(pos
.x
- ptracking_info
->pos
.x
) > (hoverwidth
/ 2.0)) ||
734 (abs(pos
.y
- ptracking_info
->pos
.y
) > (hoverheight
/ 2.0)))
736 /* record this new position as the current position and reset */
737 /* the iHoverTime variable to 0 */
738 ptracking_info
->pos
= pos
;
744 ScreenToClient(hwnd
, &posClient
);
746 if (ptracking_info
->tme
.dwFlags
& TME_NONCLIENT
)
748 PostMessageW(ptracking_info
->tme
.hwndTrack
, WM_NCMOUSEHOVER
,
749 get_key_state(), MAKELPARAM( posClient
.x
, posClient
.y
));
753 PostMessageW(ptracking_info
->tme
.hwndTrack
, WM_MOUSEHOVER
,
754 get_key_state(), MAKELPARAM( posClient
.x
, posClient
.y
));
757 /* stop tracking mouse hover */
758 ptracking_info
->tme
.dwFlags
&= ~TME_HOVER
;
762 /* stop the timer if the tracking list is empty */
763 if (!(ptracking_info
->tme
.dwFlags
& (TME_HOVER
| TME_LEAVE
)))
765 KillTimer(0, ptracking_info
->timer
);
766 RtlZeroMemory(ptracking_info
,sizeof(USER32_TRACKINGLIST
));
771 /***********************************************************************
772 * TrackMouseEvent [USER32]
774 * Requests notification of mouse events
776 * During mouse tracking WM_MOUSEHOVER or WM_MOUSELEAVE events are posted
777 * to the hwnd specified in the ptme structure. After the event message
778 * is posted to the hwnd, the entry in the queue is removed.
780 * If the current hwnd isn't ptme->hwndTrack the TME_HOVER flag is completely
781 * ignored. The TME_LEAVE flag results in a WM_MOUSELEAVE message being posted
782 * immediately and the TME_LEAVE flag being ignored.
785 * ptme [I,O] pointer to TRACKMOUSEEVENT information structure.
798 LPTRACKMOUSEEVENT ptme
)
803 PUSER32_TRACKINGLIST ptracking_info
;
805 TRACE("%lx, %lx, %p, %lx\n", ptme
->cbSize
, ptme
->dwFlags
, ptme
->hwndTrack
, ptme
->dwHoverTime
);
807 if (ptme
->cbSize
!= sizeof(TRACKMOUSEEVENT
)) {
808 WARN("wrong TRACKMOUSEEVENT size from app\n");
809 SetLastError(ERROR_INVALID_PARAMETER
);
813 ptracking_info
= & User32GetThreadData()->tracking_info
;
815 /* fill the TRACKMOUSEEVENT struct with the current tracking for the given hwnd */
816 if (ptme
->dwFlags
& TME_QUERY
)
818 *ptme
= ptracking_info
->tme
;
819 ptme
->cbSize
= sizeof(TRACKMOUSEEVENT
);
821 return TRUE
; /* return here, TME_QUERY is retrieving information */
824 if (!IsWindow(ptme
->hwndTrack
))
826 SetLastError(ERROR_INVALID_WINDOW_HANDLE
);
830 hover_time
= ptme
->dwHoverTime
;
832 /* if HOVER_DEFAULT was specified replace this with the systems current value */
833 if (hover_time
== HOVER_DEFAULT
|| hover_time
== 0)
835 SystemParametersInfoW(SPI_GETMOUSEHOVERTIME
, 0, &hover_time
, 0);
839 hwnd
= WindowFromPoint(pos
);
841 if (ptme
->dwFlags
& ~(TME_CANCEL
| TME_HOVER
| TME_LEAVE
| TME_NONCLIENT
))
843 FIXME("Unknown flag(s) %08lx\n", ptme
->dwFlags
& ~(TME_CANCEL
| TME_HOVER
| TME_LEAVE
| TME_NONCLIENT
));
846 if (ptme
->dwFlags
& TME_CANCEL
)
848 if (ptracking_info
->tme
.hwndTrack
== ptme
->hwndTrack
)
850 ptracking_info
->tme
.dwFlags
&= ~(ptme
->dwFlags
& ~TME_CANCEL
);
852 /* if we aren't tracking on hover or leave remove this entry */
853 if (!(ptracking_info
->tme
.dwFlags
& (TME_HOVER
| TME_LEAVE
)))
855 KillTimer(0, ptracking_info
->timer
);
856 RtlZeroMemory(ptracking_info
,sizeof(USER32_TRACKINGLIST
));
860 if (ptme
->hwndTrack
== hwnd
)
862 /* Adding new mouse event to the tracking list */
863 ptracking_info
->tme
= *ptme
;
864 ptracking_info
->tme
.dwHoverTime
= hover_time
;
866 /* Initialize HoverInfo variables even if not hover tracking */
867 ptracking_info
->pos
= pos
;
869 if (!ptracking_info
->timer
)
871 ptracking_info
->timer
= SetTimer(0, 0, hover_time
, TrackMouseEventProc
);