Implement TrackMouseEvent. Modified: trunk/reactos/lib/user32/misc/stubs.c Modified: trunk/reactos/lib/user32/windows/input.c _____
Modified: trunk/reactos/lib/user32/misc/stubs.c --- trunk/reactos/lib/user32/misc/stubs.c 2005-07-08 12:13:23 UTC (rev 16507) +++ trunk/reactos/lib/user32/misc/stubs.c 2005-07-08 12:15:07 UTC (rev 16508) @@ -111,19 +111,6 @@
*/ BOOL STDCALL -TrackMouseEvent( - LPTRACKMOUSEEVENT lpEventTrack) -{ - UNIMPLEMENTED; - return FALSE; -} - - -/* - * @unimplemented - */ -BOOL -STDCALL UnregisterDeviceNotification( HDEVNOTIFY Handle) { _____
Modified: trunk/reactos/lib/user32/windows/input.c --- trunk/reactos/lib/user32/windows/input.c 2005-07-08 12:13:23 UTC (rev 16507) +++ trunk/reactos/lib/user32/windows/input.c 2005-07-08 12:15:07 UTC (rev 16508) @@ -30,6 +30,21 @@
#include <user32.h>
+/* GLOBALS *******************************************************************/ + + +typedef struct __TRACKINGLIST { + TRACKMOUSEEVENT tme; + POINT pos; /* center of hover rectangle */ + INT iHoverTime; /* elapsed time the cursor has been inside of the hover rect */ +} _TRACKINGLIST; + +static _TRACKINGLIST TrackingList[10]; +static int iTrackMax = 0; +static UINT_PTR timer; +static const INT iTimerInterval = 50; /* msec for timer interval */ + + /* FUNCTIONS *****************************************************************/
@@ -126,13 +141,12 @@
/* - * @unimplemented + * @implemented */ SHORT STDCALL GetAsyncKeyState(int vKey) { - UNIMPLEMENTED; - return 0; + return (SHORT) NtUserGetAsyncKeyState((DWORD) vKey); }
@@ -656,4 +670,339 @@ NtUserSendInput(1, &Input, sizeof(INPUT)); }
+ +/********************************************************************** * + * get_key_state + */ +static WORD get_key_state(void) +{ + WORD ret = 0; + + if (GetSystemMetrics( SM_SWAPBUTTON )) + { + if (GetAsyncKeyState(VK_RBUTTON) & 0x80) ret |= MK_LBUTTON; + if (GetAsyncKeyState(VK_LBUTTON) & 0x80) ret |= MK_RBUTTON; + } + else + { + if (GetAsyncKeyState(VK_LBUTTON) & 0x80) ret |= MK_LBUTTON; + if (GetAsyncKeyState(VK_RBUTTON) & 0x80) ret |= MK_RBUTTON; + } + if (GetAsyncKeyState(VK_MBUTTON) & 0x80) ret |= MK_MBUTTON; + if (GetAsyncKeyState(VK_SHIFT) & 0x80) ret |= MK_SHIFT; + if (GetAsyncKeyState(VK_CONTROL) & 0x80) ret |= MK_CONTROL; + if (GetAsyncKeyState(VK_XBUTTON1) & 0x80) ret |= MK_XBUTTON1; + if (GetAsyncKeyState(VK_XBUTTON2) & 0x80) ret |= MK_XBUTTON2; + return ret; +} + + +static void CALLBACK TrackMouseEventProc(HWND hwndUnused, UINT uMsg, UINT_PTR idEvent, + DWORD dwTime) +{ + int i = 0; + POINT pos; + POINT posClient; + HWND hwnd; + INT nonclient; + INT hoverwidth = 0, hoverheight = 0; + RECT client; + + GetCursorPos(&pos); + hwnd = WindowFromPoint(pos); + + SystemParametersInfoA(SPI_GETMOUSEHOVERWIDTH, 0, &hoverwidth, 0); + SystemParametersInfoA(SPI_GETMOUSEHOVERHEIGHT, 0, &hoverheight, 0); + + /* loop through tracking events we are processing */ + while (i < iTrackMax) { + if (TrackingList[i].tme.dwFlags & TME_NONCLIENT) { + nonclient = 1; + } + else { + nonclient = 0; + } + + /* see if this tracking event is looking for TME_LEAVE and that the */ + /* mouse has left the window */ + if (TrackingList[i].tme.dwFlags & TME_LEAVE) { + if (TrackingList[i].tme.hwndTrack != hwnd) { + if (nonclient) { + PostMessageA(TrackingList[i].tme.hwndTrack, WM_NCMOUSELEAVE, 0, 0); + } + else { + PostMessageA(TrackingList[i].tme.hwndTrack, WM_MOUSELEAVE, 0, 0); + } + + /* remove the TME_LEAVE flag */ + TrackingList[i].tme.dwFlags ^= TME_LEAVE; + } + else { + GetClientRect(hwnd, &client); + MapWindowPoints(hwnd, NULL, (LPPOINT)&client, 2); + if(PtInRect(&client, pos)) { + if (nonclient) { + PostMessageA(TrackingList[i].tme.hwndTrack, WM_NCMOUSELEAVE, 0, 0); + /* remove the TME_LEAVE flag */ + TrackingList[i].tme.dwFlags ^= TME_LEAVE; + } + } + else { + if (!nonclient) { + PostMessageA(TrackingList[i].tme.hwndTrack, WM_MOUSELEAVE, 0, 0); + /* remove the TME_LEAVE flag */ + TrackingList[i].tme.dwFlags ^= TME_LEAVE; + } + } + } + } + + /* see if we are tracking hovering for this hwnd */ + if(TrackingList[i].tme.dwFlags & TME_HOVER) { + /* add the timer interval to the hovering time */ + TrackingList[i].iHoverTime+=iTimerInterval; + + /* has the cursor moved outside the rectangle centered around pos? */ + if((abs(pos.x - TrackingList[i].pos.x) > (hoverwidth / 2.0)) + || (abs(pos.y - TrackingList[i].pos.y) > (hoverheight / 2.0))) + { + /* record this new position as the current position and reset */ + /* the iHoverTime variable to 0 */ + TrackingList[i].pos = pos; + TrackingList[i].iHoverTime = 0; + } + + /* has the mouse hovered long enough? */ + if(TrackingList[i].iHoverTime <= TrackingList[i].tme.dwHoverTime) + { + posClient.x = pos.x; + posClient.y = pos.y; + ScreenToClient(hwnd, &posClient); + if (nonclient) { + PostMessageW(TrackingList[i].tme.hwndTrack, WM_NCMOUSEHOVER, + get_key_state(), MAKELPARAM( posClient.x, posClient.y )); + } + else { + PostMessageW(TrackingList[i].tme.hwndTrack, WM_MOUSEHOVER, + get_key_state(), MAKELPARAM( posClient.x, posClient.y )); + } + + /* stop tracking mouse hover */ + TrackingList[i].tme.dwFlags ^= TME_HOVER; + } + } + + /* see if we are still tracking TME_HOVER or TME_LEAVE for this entry */ + if((TrackingList[i].tme.dwFlags & TME_HOVER) || + (TrackingList[i].tme.dwFlags & TME_LEAVE)) { + i++; + } else { /* remove this entry from the tracking list */ + TrackingList[i] = TrackingList[--iTrackMax]; + } + } + + /* stop the timer if the tracking list is empty */ + if(iTrackMax == 0) { + KillTimer(0, timer); + timer = 0; + } +} + + +/********************************************************************** * + * TrackMouseEvent [USER32] + * + * Requests notification of mouse events + * + * During mouse tracking WM_MOUSEHOVER or WM_MOUSELEAVE events are posted + * to the hwnd specified in the ptme structure. After the event message + * is posted to the hwnd, the entry in the queue is removed. + * + * If the current hwnd isn't ptme->hwndTrack the TME_HOVER flag is completely + * ignored. The TME_LEAVE flag results in a WM_MOUSELEAVE message being posted + * immediately and the TME_LEAVE flag being ignored. + * + * PARAMS + * ptme [I,O] pointer to TRACKMOUSEEVENT information structure. + * + * RETURNS + * Success: non-zero + * Failure: zero + * + */ +/* + * @unimplemented + */ +BOOL +STDCALL +TrackMouseEvent( + LPTRACKMOUSEEVENT ptme) +{ + DWORD flags = 0; + int i = 0; + BOOL cancel = 0, hover = 0, leave = 0, query = 0, nonclient = 0, inclient = 0; + HWND hwnd; + POINT pos; + RECT client; + + + pos.x = 0; + pos.y = 0; + SetRectEmpty(&client); + + DPRINT("%lx, %lx, %p, %lx\n", ptme->cbSize, ptme->dwFlags, ptme->hwndTrack, ptme->dwHoverTime); + + if (ptme->cbSize != sizeof(TRACKMOUSEEVENT)) { + DPRINT("wrong TRACKMOUSEEVENT size from app\n"); + SetLastError(ERROR_INVALID_PARAMETER); /* FIXME not sure if this is correct */ + return FALSE; + } + + flags = ptme->dwFlags; + + /* if HOVER_DEFAULT was specified replace this with the systems current value */ + if(ptme->dwHoverTime == HOVER_DEFAULT) + SystemParametersInfoA(SPI_GETMOUSEHOVERTIME, 0, &(ptme->dwHoverTime), 0); + + GetCursorPos(&pos); + hwnd = WindowFromPoint(pos); + + if ( flags & TME_CANCEL ) { + flags &= ~ TME_CANCEL; + cancel = 1; + } + + if ( flags & TME_HOVER ) { + flags &= ~ TME_HOVER; + hover = 1; + } + + if ( flags & TME_LEAVE ) { + flags &= ~ TME_LEAVE; + leave = 1; + } + + if ( flags & TME_NONCLIENT ) { + flags &= ~ TME_NONCLIENT; + nonclient = 1; + } + + /* fill the TRACKMOUSEEVENT struct with the current tracking for the given hwnd */ + if ( flags & TME_QUERY ) { + flags &= ~ TME_QUERY; + query = 1; + i = 0; + + /* Find the tracking list entry with the matching hwnd */ + while((i < iTrackMax) && (TrackingList[i].tme.hwndTrack != ptme->hwndTrack)) { + i++; + } + + /* hwnd found, fill in the ptme struct */ + if(i < iTrackMax) + *ptme = TrackingList[i].tme; + else + ptme->dwFlags = 0; + + return TRUE; /* return here, TME_QUERY is retrieving information */ + } + + if ( flags ) + DPRINT("Unknown flag(s) %08lx\n", flags ); + + if(cancel) { + /* find a matching hwnd if one exists */ + i = 0; + + while((i < iTrackMax) && (TrackingList[i].tme.hwndTrack != ptme->hwndTrack)) { + i++; + } + + if(i < iTrackMax) { + TrackingList[i].tme.dwFlags &= ~(ptme->dwFlags & ~TME_CANCEL); + + /* if we aren't tracking on hover or leave remove this entry */ + if(!((TrackingList[i].tme.dwFlags & TME_HOVER) || + (TrackingList[i].tme.dwFlags & TME_LEAVE))) + { + TrackingList[i] = TrackingList[--iTrackMax]; + + if(iTrackMax == 0) { + KillTimer(0, timer); + timer = 0; + } + } + } + } else { + /* see if hwndTrack isn't the current window */ + if(ptme->hwndTrack != hwnd) { + if(leave) { + if(nonclient) { + PostMessageA(ptme->hwndTrack, WM_NCMOUSELEAVE, 0, 0); + } + else { + PostMessageA(ptme->hwndTrack, WM_MOUSELEAVE, 0, 0); + } + } + } else { + GetClientRect(ptme->hwndTrack, &client); + MapWindowPoints(ptme->hwndTrack, NULL, (LPPOINT)&client, 2); + if(PtInRect(&client, pos)) { + inclient = 1; + } + if(nonclient && inclient) { + PostMessageA(ptme->hwndTrack, WM_NCMOUSELEAVE, 0, 0); + return TRUE; + } + else if(!nonclient && !inclient) { + PostMessageA(ptme->hwndTrack, WM_MOUSELEAVE, 0, 0); + return TRUE; + } + + /* See if this hwnd is already being tracked and update the tracking flags */ + for(i = 0; i < iTrackMax; i++) { + if(TrackingList[i].tme.hwndTrack == ptme->hwndTrack) { + TrackingList[i].tme.dwFlags = 0; + + if(hover) { + TrackingList[i].tme.dwFlags |= TME_HOVER; + TrackingList[i].tme.dwHoverTime = ptme->dwHoverTime; + } + + if(leave) + TrackingList[i].tme.dwFlags |= TME_LEAVE; + + if(nonclient) + TrackingList[i].tme.dwFlags |= TME_NONCLIENT; + + /* reset iHoverTime as per winapi specs */ + TrackingList[i].iHoverTime = 0; + + return TRUE; + } + } + + /* if the tracking list is full return FALSE */ + if (iTrackMax == sizeof (TrackingList) / sizeof(*TrackingList)) { + return FALSE; + } + + /* Adding new mouse event to the tracking list */ + TrackingList[iTrackMax].tme = *ptme; + + /* Initialize HoverInfo variables even if not hover tracking */ + TrackingList[iTrackMax].iHoverTime = 0; + TrackingList[iTrackMax].pos = pos; + + iTrackMax++; + + if (!timer) { + timer = SetTimer(0, 0, iTimerInterval, TrackMouseEventProc); + } + } + } + + return TRUE; +} + /* EOF */