Author: jimtabor Date: Mon Nov 24 02:50:18 2014 New Revision: 65472
URL: http://svn.reactos.org/svn/reactos?rev=65472&view=rev Log: [NtUser] - Synchronize mouse messages. Part II - Dedicated to Giannis Adamopoulos and Amine Khaldi. - Additional fixes are added. - This should be more accurate, based on "Hit Testing: Which HWND is the mouse over?": http://blogs.msdn.com/b/dwayneneed/archive/2008/09/08/transparent-windows-in... - Note: Older FireFox menu item hilite select seem to work now, do not need to keep moving the mouse to keep it hilited to be selected. - Test results: https://reactos.org/sites/all/modules/reactos/testman/compare.php?ids=33709,...
Modified: trunk/reactos/win32ss/user/ntuser/keyboard.c trunk/reactos/win32ss/user/ntuser/message.c trunk/reactos/win32ss/user/ntuser/msgqueue.c trunk/reactos/win32ss/user/ntuser/msgqueue.h trunk/reactos/win32ss/user/ntuser/timer.c
Modified: trunk/reactos/win32ss/user/ntuser/keyboard.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/user/ntuser/keyboar... ============================================================================== --- trunk/reactos/win32ss/user/ntuser/keyboard.c [iso-8859-1] (original) +++ trunk/reactos/win32ss/user/ntuser/keyboard.c [iso-8859-1] Mon Nov 24 02:50:18 2014 @@ -936,10 +936,16 @@ Msg.lParam |= KF_MENUMODE << 16; }
+ // Post mouse move before posting key buttons, to keep it syned. + if (pFocusQueue->QF_flags & QF_MOUSEMOVED) + { + IntCoalesceMouseMove(pti); + } + /* Post a keyboard message */ TRACE("Posting keyboard msg %u wParam 0x%x lParam 0x%x\n", Msg.message, Msg.wParam, Msg.lParam); if (!Wnd) {ERR("Window is NULL\n");} - MsqPostMessage(pti, &Msg, TRUE, QS_KEY, 0); + MsqPostMessage(pti, &Msg, TRUE, QS_KEY, 0, dwExtraInfo); }
return TRUE; @@ -1154,7 +1160,7 @@ NewMsg.message = (lpMsg->message == WM_KEYDOWN) ? WM_CHAR : WM_SYSCHAR; NewMsg.wParam = HIWORD(lpMsg->lParam); NewMsg.lParam = LOWORD(lpMsg->lParam); - MsqPostMessage(pti, &NewMsg, FALSE, QS_KEY, 0); + MsqPostMessage(pti, &NewMsg, FALSE, QS_KEY, 0, 0); return TRUE; }
@@ -1183,7 +1189,7 @@ { TRACE("Msg: %x '%lc' (%04x) %08x\n", NewMsg.message, wch[i], wch[i], NewMsg.lParam); NewMsg.wParam = wch[i]; - MsqPostMessage(pti, &NewMsg, FALSE, QS_KEY, 0); + MsqPostMessage(pti, &NewMsg, FALSE, QS_KEY, 0, 0); } bResult = TRUE; }
Modified: trunk/reactos/win32ss/user/ntuser/message.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/user/ntuser/message... ============================================================================== --- trunk/reactos/win32ss/user/ntuser/message.c [iso-8859-1] (original) +++ trunk/reactos/win32ss/user/ntuser/message.c [iso-8859-1] Mon Nov 24 02:50:18 2014 @@ -802,6 +802,12 @@ pti->timeLast = LargeTickCount.u.LowPart; pti->pcti->tickLastMsgChecked = LargeTickCount.u.LowPart;
+ // Post mouse moves while looping through peek messages. + if (pti->MessageQueue->QF_flags & QF_MOUSEMOVED) + { + IntCoalesceMouseMove(pti); + } + /* Dispatch sent messages here. */ while ( co_MsqDispatchOneSentMessage(pti) ) { @@ -1087,7 +1093,7 @@
KeQueryTickCount(&LargeTickCount); Message.time = MsqCalculateMessageTime(&LargeTickCount); - MsqPostMessage(pti, &Message, FALSE, QS_POSTMESSAGE, 0); + MsqPostMessage(pti, &Message, FALSE, QS_POSTMESSAGE, 0, 0); return TRUE; }
@@ -1218,7 +1224,7 @@ } else { - MsqPostMessage(pti, &Message, FALSE, QS_POSTMESSAGE, 0); + MsqPostMessage(pti, &Message, FALSE, QS_POSTMESSAGE, 0, 0); } } return TRUE; @@ -1411,6 +1417,7 @@
CLEANUP: if (Window) UserDerefObjectCo(Window); + // Current Thread and it's a Copy Data message, then free kernel memory. if ( !ptiSendTo && Msg == WM_COPYDATA ) { ExFreePool((PVOID) lParam); @@ -1677,7 +1684,7 @@ END_CLEANUP; }
- +#if 0 /* This HACK function posts a message if the destination's message queue belongs to another thread, otherwise it sends the message. It does not support broadcast @@ -1721,6 +1728,7 @@
return (LRESULT)Result; } +#endif
static LRESULT FASTCALL co_IntDoSendMessage( HWND hWnd,
Modified: trunk/reactos/win32ss/user/ntuser/msgqueue.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/user/ntuser/msgqueu... ============================================================================== --- trunk/reactos/win32ss/user/ntuser/msgqueue.c [iso-8859-1] (original) +++ trunk/reactos/win32ss/user/ntuser/msgqueue.c [iso-8859-1] Mon Nov 24 02:50:18 2014 @@ -15,6 +15,9 @@
static PPAGED_LOOKASIDE_LIST pgMessageLookasideList; PUSER_MESSAGE_QUEUE gpqCursor; +ULONG_PTR gdwMouseMoveExtraInfo = 0; +DWORD gdwMouseMoveTimeStamp = 0; +
/* FUNCTIONS *****************************************************************/
@@ -311,6 +314,36 @@ } }
+/* + Get down key states from the queue of prior processed input message key states. + + This fixes the left button dragging on the desktop and release sticking outline issue. + USB Tablet pointer seems to stick the most and leaves the box outline displayed. + */ +WPARAM FASTCALL +MsqGetDownKeyState(PUSER_MESSAGE_QUEUE MessageQueue) +{ + WPARAM ret = 0; + + if (gspv.bMouseBtnSwap) + { + if (IS_KEY_DOWN(MessageQueue->afKeyState, VK_RBUTTON)) ret |= MK_LBUTTON; + if (IS_KEY_DOWN(MessageQueue->afKeyState, VK_LBUTTON)) ret |= MK_RBUTTON; + } + else + { + if (IS_KEY_DOWN(MessageQueue->afKeyState, VK_LBUTTON)) ret |= MK_LBUTTON; + if (IS_KEY_DOWN(MessageQueue->afKeyState, VK_RBUTTON)) ret |= MK_RBUTTON; + } + + if (IS_KEY_DOWN(MessageQueue->afKeyState, VK_MBUTTON)) ret |= MK_MBUTTON; + if (IS_KEY_DOWN(MessageQueue->afKeyState, VK_SHIFT)) ret |= MK_SHIFT; + if (IS_KEY_DOWN(MessageQueue->afKeyState, VK_CONTROL)) ret |= MK_CONTROL; + if (IS_KEY_DOWN(MessageQueue->afKeyState, VK_XBUTTON1)) ret |= MK_XBUTTON1; + if (IS_KEY_DOWN(MessageQueue->afKeyState, VK_XBUTTON2)) ret |= MK_XBUTTON2; + return ret; +} + HANDLE FASTCALL IntMsqSetWakeMask(DWORD WakeMask) { @@ -397,26 +430,18 @@ VOID FASTCALL ClearMsgBitsMask(PTHREADINFO pti, UINT MessageBits) { - PUSER_MESSAGE_QUEUE Queue; UINT ClrMask = 0;
- Queue = pti->MessageQueue; - if (MessageBits & QS_KEY) { if (--pti->nCntsQBits[QSRosKey] == 0) ClrMask |= QS_KEY; } - if (MessageBits & QS_MOUSEMOVE) // ReactOS hard coded. + if (MessageBits & QS_MOUSEMOVE) { // Account for tracking mouse moves.. if (pti->nCntsQBits[QSRosMouseMove]) { pti->nCntsQBits[QSRosMouseMove] = 0; // Throttle down count. Up to > 3:1 entries are ignored. - } - // Handle mouse move bits here. - if (Queue->MouseMoved) - { ClrMask |= QS_MOUSEMOVE; - Queue->MouseMoved = FALSE; } } if (MessageBits & QS_MOUSEBUTTON) @@ -472,10 +497,11 @@ }
/* - Post Mouse Move. + Post the move or update the message still pending to be processed. + Do not overload the queue with mouse move messages. */ VOID FASTCALL -MsqPostMouseMove(PTHREADINFO pti, MSG* Msg) +MsqPostMouseMove(PTHREADINFO pti, MSG* Msg, LONG_PTR ExtraInfo) { PUSER_MESSAGE Message; PLIST_ENTRY ListHead; @@ -483,22 +509,59 @@
ListHead = &MessageQueue->HardwareMessagesListHead;
- MessageQueue->MouseMoved = TRUE; - + // Do nothing if empty. if (!IsListEmpty(ListHead->Flink)) - { // Look at the end of the list, + { + // Look at the end of the list, Message = CONTAINING_RECORD(ListHead->Blink, USER_MESSAGE, ListEntry); - // If the mouse move message is existing, + + // If the mouse move message is existing on the list, if (Message->Msg.message == WM_MOUSEMOVE) { - TRACE("Post Old MM Message in Q\n"); - Message->Msg = *Msg; // Overwrite the message with updated data! + // Overwrite the message with updated data! + Message->Msg = *Msg; + MsqWakeQueue(pti, QS_MOUSEMOVE, TRUE); return; } } - TRACE("Post New MM Message to Q\n"); - MsqPostMessage(pti, Msg, TRUE, QS_MOUSEMOVE, 0); + + MsqPostMessage(pti, Msg, TRUE, QS_MOUSEMOVE, 0, ExtraInfo); +} + +/* + Bring together the mouse move message. + Named "Coalesce" from Amine email ;^) (jt). + */ +VOID FASTCALL +IntCoalesceMouseMove(PTHREADINFO pti) +{ + MSG Msg; + LARGE_INTEGER LargeTickCount; + + // Force time stamp to update, keeping message time in sync. + if (gdwMouseMoveTimeStamp == 0) + { + KeQueryTickCount(&LargeTickCount); + gdwMouseMoveTimeStamp = MsqCalculateMessageTime(&LargeTickCount); + } + + // Build mouse move message. + Msg.hwnd = NULL; + Msg.message = WM_MOUSEMOVE; + Msg.wParam = 0; + Msg.lParam = MAKELONG(gpsi->ptCursor.x, gpsi->ptCursor.y); + Msg.time = gdwMouseMoveTimeStamp; + Msg.pt = gpsi->ptCursor; + + // Post the move. + MsqPostMouseMove(pti, &Msg, gdwMouseMoveExtraInfo); + + // Zero the time stamp. + gdwMouseMoveTimeStamp = 0; + + // Clear flag since the move was posted. + pti->MessageQueue->QF_flags &= ~QF_MOUSEMOVED; }
VOID FASTCALL @@ -626,7 +689,10 @@ gpqCursor = MessageQueue;
/* Mouse move is a special case */ - MsqPostMouseMove(pti, Msg); + MessageQueue->QF_flags |= QF_MOUSEMOVED; + gdwMouseMoveExtraInfo = dwExtraInfo; + gdwMouseMoveTimeStamp = Msg->time; + MsqWakeQueue(pti, QS_MOUSEMOVE, TRUE); } else { @@ -636,8 +702,15 @@ // ptiLastInput = pti; // Once this is set during Reboot or Shutdown, this prevents the exit window having foreground. // Find all the Move Mouse calls and fix mouse set active focus issues...... } + + // Post mouse move before posting mouse buttons, keep it in sync. + if (pti->MessageQueue->QF_flags & QF_MOUSEMOVED) + { + IntCoalesceMouseMove(pti); + } + TRACE("Posting mouse message to hwnd=%p!\n", UserHMGetHandle(pwnd)); - MsqPostMessage(pti, Msg, TRUE, QS_MOUSEBUTTON, 0); + MsqPostMessage(pti, Msg, TRUE, QS_MOUSEBUTTON, 0, dwExtraInfo); } } else if (hdcScreen) @@ -1207,7 +1280,8 @@ MSG* Msg, BOOLEAN HardwareMessage, DWORD MessageBits, - DWORD dwQEvent) + DWORD dwQEvent, + LONG_PTR ExtraInfo) { PUSER_MESSAGE Message; PUSER_MESSAGE_QUEUE MessageQueue; @@ -1244,6 +1318,7 @@
if (Msg->message == WM_HOTKEY) MessageBits |= QS_HOTKEY; // Justin Case, just set it. Message->dwQEvent = dwQEvent; + Message->ExtraInfo = ExtraInfo; Message->QS_Flags = MessageBits; Message->pti = pti; MsqWakeQueue(pti, MessageBits, TRUE); @@ -1375,12 +1450,13 @@ } else { - pwndMsg = co_WinPosWindowFromPoint(NULL, &msg->pt, &hittest, FALSE);//TRUE); + pwndMsg = co_WinPosWindowFromPoint(pwndMsg, &msg->pt, &hittest, FALSE); }
TRACE("Got mouse message for %p, hittest: 0x%x\n", msg->hwnd, hittest);
- if (pwndMsg == NULL || pwndMsg->head.pti != pti) + // Null window or not the same "Hardware" message queue. + if (pwndMsg == NULL || pwndMsg->head.pti->MessageQueue != pti->MessageQueue) { /* Remove and ignore the message */ *RemoveMessages = TRUE; @@ -1469,6 +1545,12 @@ { TRACE("Message out of range!!!\n"); RETURN(FALSE); + } + + // Update mouse move down keys. + if (message == WM_MOUSEMOVE) + { + msg->wParam = MsqGetDownKeyState(MessageQueue); } }
@@ -1739,7 +1821,8 @@ */ if ( ( !Window || // 1 ( Window == PWND_BOTTOM && CurrentMessage->Msg.hwnd == NULL ) || // 2 - ( Window != PWND_BOTTOM && Window->head.h == CurrentMessage->Msg.hwnd ) ) && // 3 + ( Window != PWND_BOTTOM && Window->head.h == CurrentMessage->Msg.hwnd ) || // 3 + ( CurrentMessage->Msg.message == WM_MOUSEMOVE ) ) && // Null window for mouse moves. ( ( ( MsgFilterLow == 0 && MsgFilterHigh == 0 ) && CurrentMessage->QS_Flags & QSflags ) || ( MsgFilterLow <= CurrentMessage->Msg.message && MsgFilterHigh >= CurrentMessage->Msg.message ) ) ) {
Modified: trunk/reactos/win32ss/user/ntuser/msgqueue.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/user/ntuser/msgqueu... ============================================================================== --- trunk/reactos/win32ss/user/ntuser/msgqueue.h [iso-8859-1] (original) +++ trunk/reactos/win32ss/user/ntuser/msgqueue.h [iso-8859-1] Mon Nov 24 02:50:18 2014 @@ -51,9 +51,7 @@
/* Queue for hardware messages for the queue. */ LIST_ENTRY HardwareMessagesListHead; - /* True if a WM_MOUSEMOVE is pending */ - BOOLEAN MouseMoved; - /* Current WM_MOUSEMOVE message */ + /* Last click message for translating double clicks */ MSG msgDblClk; /* Current capture window for this queue. */ PWND spwndCapture; @@ -92,7 +90,7 @@ #define QF_FMENUSTATUSBREAK 0x00000004 #define QF_FMENUSTATUS 0x00000008 #define QF_FF10STATUS 0x00000010 -#define QF_MOUSEMOVED 0x00000020 // See MouseMoved. +#define QF_MOUSEMOVED 0x00000020 #define QF_ACTIVATIONCHANGE 0x00000040 #define QF_TABSWITCHING 0x00000080 #define QF_KEYSTATERESET 0x00000100 @@ -122,7 +120,7 @@ UINT uTimeout, BOOL Block, INT HookMessage, ULONG_PTR *uResult); PUSER_MESSAGE FASTCALL MsqCreateMessage(LPMSG Msg); VOID FASTCALL MsqDestroyMessage(PUSER_MESSAGE Message); -VOID FASTCALL MsqPostMessage(PTHREADINFO, MSG*, BOOLEAN, DWORD, DWORD); +VOID FASTCALL MsqPostMessage(PTHREADINFO, MSG*, BOOLEAN, DWORD, DWORD, LONG_PTR); VOID FASTCALL MsqPostQuitMessage(PTHREADINFO pti, ULONG ExitCode); BOOLEAN APIENTRY MsqPeekMessage(IN PTHREADINFO pti, @@ -186,6 +184,7 @@ BOOL HasPackedLParam, INT HookMessage);
+VOID FASTCALL IntCoalesceMouseMove(PTHREADINFO); LRESULT FASTCALL IntDispatchMessage(MSG* Msg); BOOL FASTCALL IntTranslateKbdMessage(LPMSG lpMsg, UINT flags); VOID FASTCALL co_MsqInsertMouseMessage(MSG* Msg, DWORD flags, ULONG_PTR dwExtraInfo, BOOL Hook); @@ -246,6 +245,7 @@ VOID FASTCALL MsqWakeQueue(PTHREADINFO,DWORD,BOOL); VOID FASTCALL ClearMsgBitsMask(PTHREADINFO,UINT); BOOL FASTCALL IntCallMsgFilter(LPMSG,INT); +WPARAM FASTCALL MsqGetDownKeyState(PUSER_MESSAGE_QUEUE);
int UserShowCursor(BOOL bShow); PCURICON_OBJECT
Modified: trunk/reactos/win32ss/user/ntuser/timer.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/user/ntuser/timer.c... ============================================================================== --- trunk/reactos/win32ss/user/ntuser/timer.c [iso-8859-1] (original) +++ trunk/reactos/win32ss/user/ntuser/timer.c [iso-8859-1] Mon Nov 24 02:50:18 2014 @@ -320,7 +320,7 @@ { if (pDesk->htEx == HTCLIENT) // In a client area. { - wParam = UserGetMouseButtonsState(); + wParam = MsqGetDownKeyState(pWnd->head.pti->MessageQueue); Msg = WM_MOUSEHOVER;
if (pWnd->ExStyle & WS_EX_LAYOUTRTL) @@ -405,7 +405,7 @@ Msg.wParam = (WPARAM) pTmr->nID; Msg.lParam = (LPARAM) pTmr->pfn;
- MsqPostMessage(pti, &Msg, FALSE, (QS_POSTMESSAGE|QS_ALLPOSTMESSAGE), 0); + MsqPostMessage(pti, &Msg, FALSE, (QS_POSTMESSAGE|QS_ALLPOSTMESSAGE), 0, 0); pTmr->flags &= ~TMRF_READY; ClearMsgBitsMask(pti, QS_TIMER); Hit = TRUE;