2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Win32k subsystem
4 * PURPOSE: Message queues
5 * FILE: win32ss/user/ntuser/msgqueue.c
6 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
12 DBG_DEFAULT_CHANNEL(UserMsgQ
);
14 /* GLOBALS *******************************************************************/
16 static PPAGED_LOOKASIDE_LIST pgMessageLookasideList
;
17 static PPAGED_LOOKASIDE_LIST pgSendMsgLookasideList
;
20 PUSER_MESSAGE_QUEUE gpqCursor
;
21 ULONG_PTR gdwMouseMoveExtraInfo
= 0;
22 DWORD gdwMouseMoveTimeStamp
= 0;
25 /* FUNCTIONS *****************************************************************/
30 MsqInitializeImpl(VOID
)
32 // Setup Post Messages
33 pgMessageLookasideList
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(PAGED_LOOKASIDE_LIST
), TAG_USRMSG
);
34 if (!pgMessageLookasideList
)
35 return STATUS_NO_MEMORY
;
36 ExInitializePagedLookasideList(pgMessageLookasideList
,
43 // Setup Send Messages
44 pgSendMsgLookasideList
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(PAGED_LOOKASIDE_LIST
), TAG_USRMSG
);
45 if (!pgSendMsgLookasideList
)
46 return STATUS_NO_MEMORY
;
47 ExInitializePagedLookasideList(pgSendMsgLookasideList
,
51 sizeof(USER_SENT_MESSAGE
),
55 InitializeListHead(&usmList
);
57 return(STATUS_SUCCESS
);
61 IntTopLevelWindowFromPoint(INT x
, INT y
)
63 PWND pWnd
, pwndDesktop
;
65 /* Get the desktop window */
66 pwndDesktop
= UserGetDesktopWindow();
70 /* Loop all top level windows */
71 for (pWnd
= pwndDesktop
->spwndChild
;
73 pWnd
= pWnd
->spwndNext
)
75 if (pWnd
->state2
& WNDS2_INDESTROY
|| pWnd
->state
& WNDS_DESTROYED
)
77 TRACE("The Window is in DESTROY!\n");
81 if ((pWnd
->style
& WS_VISIBLE
) &&
82 (pWnd
->ExStyle
& (WS_EX_LAYERED
|WS_EX_TRANSPARENT
)) != (WS_EX_LAYERED
|WS_EX_TRANSPARENT
) &&
83 IntPtInWindow(pWnd
, x
, y
))
87 /* Window has not been found */
94 PCURICON_OBJECT NewCursor
,
97 PCURICON_OBJECT OldCursor
;
100 PUSER_MESSAGE_QUEUE MessageQueue
;
103 pti
= PsGetCurrentThreadWin32Thread();
104 MessageQueue
= pti
->MessageQueue
;
106 OldCursor
= MessageQueue
->CursorObject
;
108 /* Check if cursors are different */
109 if (OldCursor
== NewCursor
)
112 /* Update cursor for this message queue */
113 MessageQueue
->CursorObject
= NewCursor
;
115 /* If cursor is not visible we have nothing to do */
116 if (MessageQueue
->iCursorLevel
< 0)
119 // Fixes the error message "Not the same cursor!".
120 if (gpqCursor
== NULL
)
122 gpqCursor
= MessageQueue
;
125 /* Update cursor if this message queue controls it */
126 pWnd
= IntTopLevelWindowFromPoint(gpsi
->ptCursor
.x
, gpsi
->ptCursor
.y
);
127 if (pWnd
&& pWnd
->head
.pti
->MessageQueue
== MessageQueue
)
129 /* Get the screen DC */
130 if (!(hdcScreen
= IntGetScreenDC()))
137 /* Call GDI to set the new screen cursor */
138 PCURICON_OBJECT CursorFrame
= NewCursor
;
139 if(NewCursor
->CURSORF_flags
& CURSORF_ACON
)
141 FIXME("Should animate the cursor, using only the first frame now.\n");
142 CursorFrame
= ((PACON
)NewCursor
)->aspcur
[0];
144 GreSetPointerShape(hdcScreen
,
145 CursorFrame
->hbmAlpha
? NULL
: NewCursor
->hbmMask
,
146 CursorFrame
->hbmAlpha
? NewCursor
->hbmAlpha
: NewCursor
->hbmColor
,
147 CursorFrame
->xHotspot
,
148 CursorFrame
->yHotspot
,
151 CursorFrame
->hbmAlpha
? SPS_ALPHA
: 0);
153 else /* Note: OldCursor != NewCursor so we have to hide cursor */
155 /* Remove the cursor */
156 GreMovePointer(hdcScreen
, -1, -1);
157 TRACE("Removing pointer!\n");
159 IntGetSysCursorInfo()->CurrentCursorObject
= NewCursor
;
162 /* Return the old cursor */
166 /* Called from NtUserCallOneParam with Routine ONEPARAM_ROUTINE_SHOWCURSOR
167 * User32 macro NtUserShowCursor */
168 int UserShowCursor(BOOL bShow
)
172 PUSER_MESSAGE_QUEUE MessageQueue
;
175 if (!(hdcScreen
= IntGetScreenDC()))
177 return -1; /* No mouse */
180 pti
= PsGetCurrentThreadWin32Thread();
181 MessageQueue
= pti
->MessageQueue
;
184 MessageQueue
->iCursorLevel
+= bShow
? 1 : -1;
185 pti
->iCursorLevel
+= bShow
? 1 : -1;
187 /* Check for trivial cases */
188 if ((bShow
&& MessageQueue
->iCursorLevel
!= 0) ||
189 (!bShow
&& MessageQueue
->iCursorLevel
!= -1))
191 /* Note: w don't update global info here because it is used only
192 internally to check if cursor is visible */
193 return MessageQueue
->iCursorLevel
;
196 /* Check if cursor is above window owned by this MessageQueue */
197 pWnd
= IntTopLevelWindowFromPoint(gpsi
->ptCursor
.x
, gpsi
->ptCursor
.y
);
198 if (pWnd
&& pWnd
->head
.pti
->MessageQueue
== MessageQueue
)
202 /* Show the pointer */
203 GreMovePointer(hdcScreen
, gpsi
->ptCursor
.x
, gpsi
->ptCursor
.y
);
204 TRACE("Showing pointer!\n");
208 /* Remove the pointer */
209 GreMovePointer(hdcScreen
, -1, -1);
210 TRACE("Removing pointer!\n");
213 /* Update global info */
214 IntGetSysCursorInfo()->ShowingCursor
= MessageQueue
->iCursorLevel
;
217 return MessageQueue
->iCursorLevel
;
221 UserGetKeyState(DWORD dwKey
)
225 PUSER_MESSAGE_QUEUE MessageQueue
;
227 pti
= PsGetCurrentThreadWin32Thread();
228 MessageQueue
= pti
->MessageQueue
;
232 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, dwKey
))
233 dwRet
|= 0xFF80; // If down, windows returns 0xFF80.
234 if (IS_KEY_LOCKED(MessageQueue
->afKeyState
, dwKey
))
239 EngSetLastError(ERROR_INVALID_PARAMETER
);
244 /* change the input key state for a given key */
246 UpdateKeyState(PUSER_MESSAGE_QUEUE MessageQueue
, WORD wVk
, BOOL bIsDown
)
248 TRACE("UpdateKeyState wVk: %u, bIsDown: %d\n", wVk
, bIsDown
);
252 /* If it's first key down event, xor lock bit */
253 if (!IS_KEY_DOWN(MessageQueue
->afKeyState
, wVk
))
254 SET_KEY_LOCKED(MessageQueue
->afKeyState
, wVk
, !IS_KEY_LOCKED(MessageQueue
->afKeyState
, wVk
));
256 SET_KEY_DOWN(MessageQueue
->afKeyState
, wVk
, TRUE
);
257 MessageQueue
->afKeyRecentDown
[wVk
/ 8] |= (1 << (wVk
% 8));
260 SET_KEY_DOWN(MessageQueue
->afKeyState
, wVk
, FALSE
);
263 /* update the input key state for a keyboard message */
265 UpdateKeyStateFromMsg(PUSER_MESSAGE_QUEUE MessageQueue
, MSG
* msg
)
270 TRACE("UpdateKeyStateFromMsg message:%u\n", msg
->message
);
272 switch (msg
->message
)
278 UpdateKeyState(MessageQueue
, VK_LBUTTON
, down
);
284 UpdateKeyState(MessageQueue
, VK_MBUTTON
, down
);
290 UpdateKeyState(MessageQueue
, VK_RBUTTON
, down
);
296 if (msg
->wParam
== XBUTTON1
)
297 UpdateKeyState(MessageQueue
, VK_XBUTTON1
, down
);
298 else if (msg
->wParam
== XBUTTON2
)
299 UpdateKeyState(MessageQueue
, VK_XBUTTON2
, down
);
307 key
= (UCHAR
)msg
->wParam
;
308 UpdateKeyState(MessageQueue
, key
, down
);
313 down
= IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_LCONTROL
) || IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_RCONTROL
);
314 UpdateKeyState(MessageQueue
, VK_CONTROL
, down
);
318 down
= IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_LMENU
) || IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_RMENU
);
319 UpdateKeyState(MessageQueue
, VK_MENU
, down
);
323 down
= IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_LSHIFT
) || IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_RSHIFT
);
324 UpdateKeyState(MessageQueue
, VK_SHIFT
, down
);
332 Get down key states from the queue of prior processed input message key states.
334 This fixes the left button dragging on the desktop and release sticking outline issue.
335 USB Tablet pointer seems to stick the most and leaves the box outline displayed.
338 MsqGetDownKeyState(PUSER_MESSAGE_QUEUE MessageQueue
)
342 if (gspv
.bMouseBtnSwap
)
344 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_RBUTTON
)) ret
|= MK_LBUTTON
;
345 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_LBUTTON
)) ret
|= MK_RBUTTON
;
349 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_LBUTTON
)) ret
|= MK_LBUTTON
;
350 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_RBUTTON
)) ret
|= MK_RBUTTON
;
353 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_MBUTTON
)) ret
|= MK_MBUTTON
;
354 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_SHIFT
)) ret
|= MK_SHIFT
;
355 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_CONTROL
)) ret
|= MK_CONTROL
;
356 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_XBUTTON1
)) ret
|= MK_XBUTTON1
;
357 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_XBUTTON2
)) ret
|= MK_XBUTTON2
;
362 IntMsqSetWakeMask(DWORD WakeMask
)
364 PTHREADINFO Win32Thread
;
365 HANDLE MessageEventHandle
;
366 DWORD dwFlags
= HIWORD(WakeMask
);
368 Win32Thread
= PsGetCurrentThreadWin32Thread();
369 if (Win32Thread
== NULL
|| Win32Thread
->MessageQueue
== NULL
)
372 // Win32Thread->pEventQueueServer; IntMsqSetWakeMask returns Win32Thread->hEventQueueClient
373 MessageEventHandle
= Win32Thread
->hEventQueueClient
;
375 if (Win32Thread
->pcti
)
377 if ( (Win32Thread
->pcti
->fsChangeBits
& LOWORD(WakeMask
)) ||
378 ( (dwFlags
& MWMO_INPUTAVAILABLE
) && (Win32Thread
->pcti
->fsWakeBits
& LOWORD(WakeMask
)) ) )
380 ERR("Chg 0x%x Wake 0x%x Mask 0x%x\n",Win32Thread
->pcti
->fsChangeBits
, Win32Thread
->pcti
->fsWakeBits
, WakeMask
);
381 KeSetEvent(Win32Thread
->pEventQueueServer
, IO_NO_INCREMENT
, FALSE
); // Wake it up!
382 return MessageEventHandle
;
388 return MessageEventHandle
;
392 IntMsqClearWakeMask(VOID
)
394 PTHREADINFO Win32Thread
;
396 Win32Thread
= PsGetCurrentThreadWin32Thread();
397 if (Win32Thread
== NULL
|| Win32Thread
->MessageQueue
== NULL
)
399 // Very hacky, but that is what they do.
400 Win32Thread
->pcti
->fsWakeBits
= 0;
408 Due to the uncertainty of knowing what was set in our multilevel message queue,
409 and even if the bits are all cleared. The same as cTimers/cPaintsReady.
410 I think this is the best solution... (jt) */
412 MsqWakeQueue(PTHREADINFO pti
, DWORD MessageBits
, BOOL KeyEvent
)
414 PUSER_MESSAGE_QUEUE Queue
;
416 Queue
= pti
->MessageQueue
;
418 if (Queue
->QF_flags
& QF_INDESTROY
)
420 ERR("This Message Queue is in Destroy!\n");
422 pti
->pcti
->fsWakeBits
|= MessageBits
;
423 pti
->pcti
->fsChangeBits
|= MessageBits
;
425 // Start bit accounting to help clear the main set of bits.
426 if (MessageBits
& QS_KEY
)
428 pti
->nCntsQBits
[QSRosKey
]++;
430 if (MessageBits
& QS_MOUSE
)
432 if (MessageBits
& QS_MOUSEMOVE
) pti
->nCntsQBits
[QSRosMouseMove
]++;
433 if (MessageBits
& QS_MOUSEBUTTON
) pti
->nCntsQBits
[QSRosMouseButton
]++;
435 if (MessageBits
& QS_POSTMESSAGE
) pti
->nCntsQBits
[QSRosPostMessage
]++;
436 if (MessageBits
& QS_SENDMESSAGE
) pti
->nCntsQBits
[QSRosSendMessage
]++;
437 if (MessageBits
& QS_HOTKEY
) pti
->nCntsQBits
[QSRosHotKey
]++;
438 if (MessageBits
& QS_EVENT
) pti
->nCntsQBits
[QSRosEvent
]++;
441 KeSetEvent(pti
->pEventQueueServer
, IO_NO_INCREMENT
, FALSE
);
445 ClearMsgBitsMask(PTHREADINFO pti
, UINT MessageBits
)
449 if (MessageBits
& QS_KEY
)
451 if (--pti
->nCntsQBits
[QSRosKey
] == 0) ClrMask
|= QS_KEY
;
453 if (MessageBits
& QS_MOUSEMOVE
)
454 { // Account for tracking mouse moves..
455 if (pti
->nCntsQBits
[QSRosMouseMove
])
457 pti
->nCntsQBits
[QSRosMouseMove
] = 0; // Throttle down count. Up to > 3:1 entries are ignored.
458 ClrMask
|= QS_MOUSEMOVE
;
461 if (MessageBits
& QS_MOUSEBUTTON
)
463 if (--pti
->nCntsQBits
[QSRosMouseButton
] == 0) ClrMask
|= QS_MOUSEBUTTON
;
465 if (MessageBits
& QS_POSTMESSAGE
)
467 if (--pti
->nCntsQBits
[QSRosPostMessage
] == 0) ClrMask
|= QS_POSTMESSAGE
;
469 if (MessageBits
& QS_TIMER
) // ReactOS hard coded.
470 { // Handle timer bits here.
471 if ( pti
->cTimersReady
)
473 if (--pti
->cTimersReady
== 0) ClrMask
|= QS_TIMER
;
476 if (MessageBits
& QS_PAINT
) // ReactOS hard coded.
477 { // Handle paint bits here.
478 if ( pti
->cPaintsReady
)
480 if (--pti
->cPaintsReady
== 0) ClrMask
|= QS_PAINT
;
483 if (MessageBits
& QS_SENDMESSAGE
)
485 if (--pti
->nCntsQBits
[QSRosSendMessage
] == 0) ClrMask
|= QS_SENDMESSAGE
;
487 if (MessageBits
& QS_HOTKEY
)
489 if (--pti
->nCntsQBits
[QSRosHotKey
] == 0) ClrMask
|= QS_HOTKEY
;
491 if (MessageBits
& QS_EVENT
)
493 if (--pti
->nCntsQBits
[QSRosEvent
] == 0) ClrMask
|= QS_EVENT
;
496 pti
->pcti
->fsWakeBits
&= ~ClrMask
;
497 pti
->pcti
->fsChangeBits
&= ~ClrMask
;
501 MsqIncPaintCountQueue(PTHREADINFO pti
)
504 MsqWakeQueue(pti
, QS_PAINT
, TRUE
);
508 MsqDecPaintCountQueue(PTHREADINFO pti
)
510 ClearMsgBitsMask(pti
, QS_PAINT
);
514 Post the move or update the message still pending to be processed.
515 Do not overload the queue with mouse move messages.
518 MsqPostMouseMove(PTHREADINFO pti
, MSG
* Msg
, LONG_PTR ExtraInfo
)
520 PUSER_MESSAGE Message
;
521 PLIST_ENTRY ListHead
;
522 PUSER_MESSAGE_QUEUE MessageQueue
= pti
->MessageQueue
;
524 ListHead
= &MessageQueue
->HardwareMessagesListHead
;
526 // Do nothing if empty.
527 if (!IsListEmpty(ListHead
->Flink
))
529 // Look at the end of the list,
530 Message
= CONTAINING_RECORD(ListHead
->Blink
, USER_MESSAGE
, ListEntry
);
532 // If the mouse move message is existing on the list,
533 if (Message
->Msg
.message
== WM_MOUSEMOVE
)
535 // Overwrite the message with updated data!
538 MsqWakeQueue(pti
, QS_MOUSEMOVE
, TRUE
);
543 MsqPostMessage(pti
, Msg
, TRUE
, QS_MOUSEMOVE
, 0, ExtraInfo
);
547 Bring together the mouse move message.
548 Named "Coalesce" from Amine email ;^) (jt).
551 IntCoalesceMouseMove(PTHREADINFO pti
)
555 // Force time stamp to update, keeping message time in sync.
556 if (gdwMouseMoveTimeStamp
== 0)
558 gdwMouseMoveTimeStamp
= EngGetTickCount32();
561 // Build mouse move message.
563 Msg
.message
= WM_MOUSEMOVE
;
565 Msg
.lParam
= MAKELONG(gpsi
->ptCursor
.x
, gpsi
->ptCursor
.y
);
566 Msg
.time
= gdwMouseMoveTimeStamp
;
567 Msg
.pt
= gpsi
->ptCursor
;
570 MsqPostMouseMove(pti
, &Msg
, gdwMouseMoveExtraInfo
);
572 // Zero the time stamp.
573 gdwMouseMoveTimeStamp
= 0;
575 // Clear flag since the move was posted.
576 pti
->MessageQueue
->QF_flags
&= ~QF_MOUSEMOVED
;
580 co_MsqInsertMouseMessage(MSG
* Msg
, DWORD flags
, ULONG_PTR dwExtraInfo
, BOOL Hook
)
582 MSLLHOOKSTRUCT MouseHookData
;
584 PWND pwnd
, pwndDesktop
;
587 PUSER_MESSAGE_QUEUE MessageQueue
;
588 PSYSTEM_CURSORINFO CurInfo
;
590 Msg
->time
= EngGetTickCount32();
592 MouseHookData
.pt
.x
= LOWORD(Msg
->lParam
);
593 MouseHookData
.pt
.y
= HIWORD(Msg
->lParam
);
594 switch (Msg
->message
)
597 MouseHookData
.mouseData
= MAKELONG(0, GET_WHEEL_DELTA_WPARAM(Msg
->wParam
));
601 case WM_XBUTTONDBLCLK
:
602 case WM_NCXBUTTONDOWN
:
604 case WM_NCXBUTTONDBLCLK
:
605 MouseHookData
.mouseData
= MAKELONG(0, HIWORD(Msg
->wParam
));
608 MouseHookData
.mouseData
= 0;
612 MouseHookData
.flags
= flags
; // LLMHF_INJECTED
613 MouseHookData
.time
= Msg
->time
;
614 MouseHookData
.dwExtraInfo
= dwExtraInfo
;
616 /* If the hook procedure returned non zero, dont send the message */
619 if (co_HOOK_CallHooks(WH_MOUSE_LL
, HC_ACTION
, Msg
->message
, (LPARAM
) &MouseHookData
))
623 /* Get the desktop window */
624 pwndDesktop
= UserGetDesktopWindow();
625 if (!pwndDesktop
) return;
626 // pDesk = pwndDesktop->head.rpdesk;
628 /* Check if the mouse is captured */
629 Msg
->hwnd
= IntGetCaptureWindow();
630 if (Msg
->hwnd
!= NULL
)
632 pwnd
= UserGetWindowObject(Msg
->hwnd
);
636 pwnd
= IntTopLevelWindowFromPoint(Msg
->pt
.x
, Msg
->pt
.y
);
637 if (pwnd
) Msg
->hwnd
= pwnd
->head
.h
;
640 hdcScreen
= IntGetScreenDC();
641 CurInfo
= IntGetSysCursorInfo();
643 /* Check if we found a window */
644 if (Msg
->hwnd
!= NULL
&& pwnd
!= NULL
)
646 pti
= pwnd
->head
.pti
;
647 MessageQueue
= pti
->MessageQueue
;
649 if (MessageQueue
->QF_flags
& QF_INDESTROY
)
651 ERR("Mouse is over a Window with a Dead Message Queue!\n");
655 // Check to see if this is attached.
656 if ( pti
!= MessageQueue
->ptiMouse
&&
657 MessageQueue
->cThreads
> 1 )
659 // Set the send pti to the message queue mouse pti.
660 pti
= MessageQueue
->ptiMouse
;
663 if (Msg
->message
== WM_MOUSEMOVE
)
665 /* Check if cursor should be visible */
667 MessageQueue
->CursorObject
&&
668 MessageQueue
->iCursorLevel
>= 0)
670 /* Check if shape has changed */
671 if(CurInfo
->CurrentCursorObject
!= MessageQueue
->CursorObject
)
673 /* Call GDI to set the new screen cursor */
674 GreSetPointerShape(hdcScreen
,
675 MessageQueue
->CursorObject
->hbmAlpha
?
676 NULL
: MessageQueue
->CursorObject
->hbmMask
,
677 MessageQueue
->CursorObject
->hbmAlpha
?
678 MessageQueue
->CursorObject
->hbmAlpha
: MessageQueue
->CursorObject
->hbmColor
,
679 MessageQueue
->CursorObject
->xHotspot
,
680 MessageQueue
->CursorObject
->yHotspot
,
683 MessageQueue
->CursorObject
->hbmAlpha
? SPS_ALPHA
: 0);
686 GreMovePointer(hdcScreen
, Msg
->pt
.x
, Msg
->pt
.y
);
688 /* Check if we have to hide cursor */
689 else if (CurInfo
->ShowingCursor
>= 0)
690 GreMovePointer(hdcScreen
, -1, -1);
692 /* Update global cursor info */
693 CurInfo
->ShowingCursor
= MessageQueue
->iCursorLevel
;
694 CurInfo
->CurrentCursorObject
= MessageQueue
->CursorObject
;
695 gpqCursor
= MessageQueue
;
697 /* Mouse move is a special case */
698 MessageQueue
->QF_flags
|= QF_MOUSEMOVED
;
699 gdwMouseMoveExtraInfo
= dwExtraInfo
;
700 gdwMouseMoveTimeStamp
= Msg
->time
;
701 MsqWakeQueue(pti
, QS_MOUSEMOVE
, TRUE
);
705 if (!IntGetCaptureWindow())
707 // ERR("ptiLastInput is set\n");
708 // ptiLastInput = pti; // Once this is set during Reboot or Shutdown, this prevents the exit window having foreground.
709 // Find all the Move Mouse calls and fix mouse set active focus issues......
712 // Post mouse move before posting mouse buttons, keep it in sync.
713 if (pti
->MessageQueue
->QF_flags
& QF_MOUSEMOVED
)
715 IntCoalesceMouseMove(pti
);
718 TRACE("Posting mouse message to hwnd=%p!\n", UserHMGetHandle(pwnd
));
719 MsqPostMessage(pti
, Msg
, TRUE
, QS_MOUSEBUTTON
, 0, dwExtraInfo
);
724 /* always show cursor on background; FIXME: set default pointer */
725 GreMovePointer(hdcScreen
, Msg
->pt
.x
, Msg
->pt
.y
);
726 CurInfo
->ShowingCursor
= 0;
730 PUSER_MESSAGE FASTCALL
731 MsqCreateMessage(LPMSG Msg
)
733 PUSER_MESSAGE Message
;
735 Message
= ExAllocateFromPagedLookasideList(pgMessageLookasideList
);
741 RtlZeroMemory(Message
, sizeof(*Message
));
742 RtlMoveMemory(&Message
->Msg
, Msg
, sizeof(MSG
));
748 MsqDestroyMessage(PUSER_MESSAGE Message
)
750 TRACE("Post Destroy %d\n",PostMsgCount
);
751 if (Message
->pti
== NULL
)
753 ERR("Double Free Message\n");
756 RemoveEntryList(&Message
->ListEntry
);
758 ExFreeToPagedLookasideList(pgMessageLookasideList
, Message
);
762 PUSER_SENT_MESSAGE FASTCALL
763 AllocateUserMessage(BOOL KEvent
)
765 PUSER_SENT_MESSAGE Message
;
767 if(!(Message
= ExAllocateFromPagedLookasideList(pgSendMsgLookasideList
)))
769 ERR("AllocateUserMessage(): Not enough memory to allocate a message");
772 RtlZeroMemory(Message
, sizeof(USER_SENT_MESSAGE
));
776 Message
->pkCompletionEvent
= &Message
->CompletionEvent
;
778 KeInitializeEvent(Message
->pkCompletionEvent
, NotificationEvent
, FALSE
);
781 TRACE("AUM pti %p msg %p\n",PsGetCurrentThreadWin32Thread(),Message
);
786 FreeUserMessage(PUSER_SENT_MESSAGE Message
)
788 Message
->pkCompletionEvent
= NULL
;
790 /* Remove it from the list */
791 RemoveEntryList(&Message
->ListEntry
);
793 ExFreeToPagedLookasideList(pgSendMsgLookasideList
, Message
);
798 MsqRemoveWindowMessagesFromQueue(PWND Window
)
801 PUSER_SENT_MESSAGE SentMessage
;
802 PUSER_MESSAGE PostedMessage
;
803 PLIST_ENTRY CurrentEntry
, ListHead
;
807 pti
= Window
->head
.pti
;
809 /* remove the posted messages for this window */
810 CurrentEntry
= pti
->PostedMessagesListHead
.Flink
;
811 ListHead
= &pti
->PostedMessagesListHead
;
812 while (CurrentEntry
!= ListHead
)
814 PostedMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
, ListEntry
);
816 if (PostedMessage
->Msg
.hwnd
== Window
->head
.h
)
818 if (PostedMessage
->Msg
.message
== WM_QUIT
&& pti
->QuitPosted
== 0)
821 pti
->exitCode
= PostedMessage
->Msg
.wParam
;
823 ClearMsgBitsMask(pti
, PostedMessage
->QS_Flags
);
824 MsqDestroyMessage(PostedMessage
);
825 CurrentEntry
= pti
->PostedMessagesListHead
.Flink
;
829 CurrentEntry
= CurrentEntry
->Flink
;
833 /* remove the sent messages for this window */
834 CurrentEntry
= pti
->SentMessagesListHead
.Flink
;
835 ListHead
= &pti
->SentMessagesListHead
;
836 while (CurrentEntry
!= ListHead
)
838 SentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
, ListEntry
);
840 if(SentMessage
->Msg
.hwnd
== Window
->head
.h
)
842 ERR("Remove Window Messages %p From Sent Queue\n",SentMessage
);
843 #if 0 // Should mark these as invalid and allow the rest clean up, so far no harm by just commenting out. See CORE-9210.
844 ClearMsgBitsMask(pti
, SentMessage
->QS_Flags
);
846 /* wake the sender's thread */
847 if (SentMessage
->pkCompletionEvent
!= NULL
)
849 KeSetEvent(SentMessage
->pkCompletionEvent
, IO_NO_INCREMENT
, FALSE
);
852 if (SentMessage
->HasPackedLParam
)
854 if (SentMessage
->Msg
.lParam
)
855 ExFreePool((PVOID
)SentMessage
->Msg
.lParam
);
858 /* free the message */
859 FreeUserMessage(SentMessage
);
861 CurrentEntry
= pti
->SentMessagesListHead
.Flink
;
863 CurrentEntry
= CurrentEntry
->Flink
;
867 CurrentEntry
= CurrentEntry
->Flink
;
873 co_MsqDispatchOneSentMessage(
874 _In_ PTHREADINFO pti
)
876 PUSER_SENT_MESSAGE SaveMsg
, Message
;
881 ASSERT(pti
== PsGetCurrentThreadWin32Thread());
883 if (IsListEmpty(&pti
->SentMessagesListHead
))
888 /* remove it from the list of pending messages */
889 Entry
= RemoveHeadList(&pti
->SentMessagesListHead
);
890 Message
= CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
);
892 // Signal this message is being processed.
893 Message
->flags
|= SMF_RECEIVERBUSY
|SMF_RECEIVEDMESSAGE
;
895 SaveMsg
= pti
->pusmCurrent
;
896 pti
->pusmCurrent
= Message
;
898 // Processing a message sent to it from another thread.
899 if ( ( Message
->ptiSender
&& pti
!= Message
->ptiSender
) ||
900 ( Message
->ptiCallBackSender
&& pti
!= Message
->ptiCallBackSender
))
901 { // most likely, but, to be sure.
902 pti
->pcti
->CTI_flags
|= CTI_INSENDMESSAGE
; // Let the user know...
905 /* Now insert it to the global list of messages that can be removed Justin Case there's Trouble */
906 InsertTailList(&usmList
, &Message
->ListEntry
);
908 ClearMsgBitsMask(pti
, Message
->QS_Flags
);
910 if (Message
->HookMessage
== MSQ_ISHOOK
)
911 { // Direct Hook Call processor
912 Result
= co_CallHook( Message
->Msg
.message
, // HookId
913 (INT
)(INT_PTR
)Message
->Msg
.hwnd
, // Code
915 Message
->Msg
.lParam
);
917 else if(Message
->HookMessage
== MSQ_INJECTMODULE
)
919 Result
= IntLoadHookModule(Message
->Msg
.message
,
920 (HHOOK
)Message
->Msg
.lParam
,
921 Message
->Msg
.wParam
);
923 else if ((Message
->CompletionCallback
) &&
924 (Message
->ptiCallBackSender
== pti
))
925 { /* Call the callback routine */
926 if (Message
->QS_Flags
& QS_SMRESULT
)
928 co_IntCallSentMessageCallback(Message
->CompletionCallback
,
930 Message
->Msg
.message
,
931 Message
->CompletionCallbackContext
,
933 /* Set callback to NULL to prevent reentry */
934 Message
->CompletionCallback
= NULL
;
938 /* The message has not been processed yet, reinsert it. */
939 RemoveEntryList(&Message
->ListEntry
);
940 InsertTailList(&Message
->ptiCallBackSender
->SentMessagesListHead
, &Message
->ListEntry
);
941 // List is occupied need to set the bit.
942 MsqWakeQueue(Message
->ptiCallBackSender
, QS_SENDMESSAGE
, TRUE
);
943 ERR("Callback Message not processed yet. Requeuing the message\n"); //// <---- Need to see if this happens.
949 { /* Call the window procedure. */
950 Result
= co_IntSendMessage( Message
->Msg
.hwnd
,
951 Message
->Msg
.message
,
953 Message
->Msg
.lParam
);
956 /* If the message is a callback, insert it in the callback senders MessageQueue */
957 if (Message
->CompletionCallback
)
959 if (Message
->ptiCallBackSender
)
961 Message
->lResult
= Result
;
962 Message
->QS_Flags
|= QS_SMRESULT
;
964 /* insert it in the callers message queue */
965 RemoveEntryList(&Message
->ListEntry
);
966 InsertTailList(&Message
->ptiCallBackSender
->SentMessagesListHead
, &Message
->ListEntry
);
967 MsqWakeQueue(Message
->ptiCallBackSender
, QS_SENDMESSAGE
, TRUE
);
973 // Retrieve the result from callback.
974 if (Message
->QS_Flags
& QS_SMRESULT
)
976 Result
= Message
->lResult
;
979 /* Let the sender know the result. */
980 Message
->lResult
= Result
;
982 if (Message
->HasPackedLParam
)
984 if (Message
->Msg
.lParam
)
985 ExFreePool((PVOID
)Message
->Msg
.lParam
);
988 // Clear busy signal.
989 Message
->flags
&= ~SMF_RECEIVERBUSY
;
991 /* Notify the sender. */
992 if (Message
->pkCompletionEvent
!= NULL
)
994 KeSetEvent(Message
->pkCompletionEvent
, IO_NO_INCREMENT
, FALSE
);
997 /* free the message */
998 if (Message
->flags
& SMF_RECEIVERFREE
)
1000 TRACE("Receiver Freeing Message %p\n",Message
);
1001 FreeUserMessage(Message
);
1006 /* do not hangup on the user if this is reentering */
1007 if (!SaveMsg
) pti
->pcti
->CTI_flags
&= ~CTI_INSENDMESSAGE
;
1008 pti
->pusmCurrent
= SaveMsg
;
1014 co_MsqSendMessageAsync(PTHREADINFO ptiReceiver
,
1019 SENDASYNCPROC CompletionCallback
,
1020 ULONG_PTR CompletionCallbackContext
,
1021 BOOL HasPackedLParam
,
1025 PTHREADINFO ptiSender
;
1026 PUSER_SENT_MESSAGE Message
;
1028 if(!(Message
= AllocateUserMessage(FALSE
)))
1030 ERR("MsqSendMessageAsync(): Not enough memory to allocate a message");
1034 ptiSender
= PsGetCurrentThreadWin32Thread();
1036 Message
->Msg
.hwnd
= hwnd
;
1037 Message
->Msg
.message
= Msg
;
1038 Message
->Msg
.wParam
= wParam
;
1039 Message
->Msg
.lParam
= lParam
;
1040 Message
->pkCompletionEvent
= NULL
; // No event needed.
1041 Message
->ptiReceiver
= ptiReceiver
;
1042 Message
->ptiCallBackSender
= ptiSender
;
1043 Message
->CompletionCallback
= CompletionCallback
;
1044 Message
->CompletionCallbackContext
= CompletionCallbackContext
;
1045 Message
->HookMessage
= HookMessage
;
1046 Message
->HasPackedLParam
= HasPackedLParam
;
1047 Message
->QS_Flags
= QS_SENDMESSAGE
;
1048 Message
->flags
= SMF_RECEIVERFREE
;
1050 InsertTailList(&ptiReceiver
->SentMessagesListHead
, &Message
->ListEntry
);
1051 MsqWakeQueue(ptiReceiver
, QS_SENDMESSAGE
, TRUE
);
1057 co_MsqSendMessage(PTHREADINFO ptirec
,
1068 PUSER_SENT_MESSAGE SaveMsg
, Message
;
1069 NTSTATUS WaitStatus
;
1070 LARGE_INTEGER Timeout
;
1073 BOOLEAN SwapStateEnabled
;
1074 LRESULT Result
= 0; //// Result could be trashed. ////
1076 pti
= PsGetCurrentThreadWin32Thread();
1077 ASSERT(pti
!= ptirec
);
1078 ASSERT(ptirec
->pcti
); // Send must have a client side to receive it!!!!
1080 /* Don't send from or to a dying thread */
1081 if (pti
->TIF_flags
& TIF_INCLEANUP
|| ptirec
->TIF_flags
& TIF_INCLEANUP
)
1083 // Unless we are dying and need to tell our parents.
1084 if (pti
->TIF_flags
& TIF_INCLEANUP
&& !(ptirec
->TIF_flags
& TIF_INCLEANUP
))
1086 // Parent notify is the big one. Fire and forget!
1087 TRACE("Send message from dying thread %u\n", Msg
);
1088 co_MsqSendMessageAsync(ptirec
, Wnd
, Msg
, wParam
, lParam
, NULL
, 0, FALSE
, HookMessage
);
1090 if (uResult
) *uResult
= -1;
1091 TRACE("MsqSM: Msg %u Current pti %lu or Rec pti %lu\n", Msg
, pti
->TIF_flags
& TIF_INCLEANUP
, ptirec
->TIF_flags
& TIF_INCLEANUP
);
1092 return STATUS_UNSUCCESSFUL
;
1095 if (IsThreadSuspended(ptirec
))
1097 ERR("Sending to Suspended Thread Msg %lx\n",Msg
);
1098 if (uResult
) *uResult
= -1;
1099 return STATUS_UNSUCCESSFUL
;
1102 // Should we do the same for No Wait?
1103 if ( HookMessage
== MSQ_NORMAL
)
1105 pWnd
= ValidateHwndNoErr(Wnd
);
1107 // These can not cross International Border lines!
1108 if ( pti
->ppi
!= ptirec
->ppi
&& pWnd
)
1112 // Handle the special case when working with password transfers across bordering processes.
1114 case EM_SETPASSWORDCHAR
:
1116 // Look for edit controls setup for passwords.
1117 if ( gpsi
->atomSysClass
[ICLS_EDIT
] == pWnd
->pcls
->atomClassName
&& // Use atomNVClassName.
1118 pWnd
->style
& ES_PASSWORD
)
1120 if (uResult
) *uResult
= -1;
1121 ERR("Running across the border without a passport!\n");
1122 EngSetLastError(ERROR_ACCESS_DENIED
);
1123 return STATUS_UNSUCCESSFUL
;
1127 if (uResult
) *uResult
= -1;
1128 ERR("Running across the border without a passport!\n");
1129 return STATUS_UNSUCCESSFUL
;
1133 // These can not cross State lines!
1134 if ( Msg
== WM_CREATE
|| Msg
== WM_NCCREATE
)
1136 if (uResult
) *uResult
= -1;
1137 ERR("Can not tell the other State we have Create!\n");
1138 return STATUS_UNSUCCESSFUL
;
1142 if(!(Message
= AllocateUserMessage(TRUE
)))
1144 ERR("MsqSendMessage(): Not enough memory to allocate a message\n");
1145 if (uResult
) *uResult
= -1;
1146 return STATUS_INSUFFICIENT_RESOURCES
;
1149 Timeout
.QuadPart
= Int32x32To64(-10000,uTimeout
); // Pass SMTO test with a TO of 0x80000000.
1150 TRACE("Timeout val %lld\n",Timeout
.QuadPart
);
1152 Message
->Msg
.hwnd
= Wnd
;
1153 Message
->Msg
.message
= Msg
;
1154 Message
->Msg
.wParam
= wParam
;
1155 Message
->Msg
.lParam
= lParam
;
1156 Message
->ptiReceiver
= ptirec
;
1157 Message
->ptiSender
= pti
;
1158 Message
->HookMessage
= HookMessage
;
1159 Message
->QS_Flags
= QS_SENDMESSAGE
;
1161 SaveMsg
= pti
->pusmSent
;
1162 pti
->pusmSent
= Message
;
1164 /* Queue it in the destination's message queue */
1165 InsertTailList(&ptirec
->SentMessagesListHead
, &Message
->ListEntry
);
1167 MsqWakeQueue(ptirec
, QS_SENDMESSAGE
, TRUE
);
1169 // First time in, turn off swapping of the stack.
1170 if (pti
->cEnterCount
== 0)
1172 SwapStateEnabled
= KeSetKernelStackSwapEnable(FALSE
);
1178 PVOID WaitObjects
[2];
1180 WaitObjects
[0] = Message
->pkCompletionEvent
; // Wait 0
1181 WaitObjects
[1] = ptirec
->pEThread
; // Wait 1
1185 WaitStatus
= KeWaitForMultipleObjects( 2,
1191 (uTimeout
? &Timeout
: NULL
),
1196 if (WaitStatus
== STATUS_TIMEOUT
)
1198 /* Look up if the message has not yet dispatched, if so
1199 make sure it can't pass a result and it must not set the completion event anymore */
1200 Entry
= ptirec
->SentMessagesListHead
.Flink
;
1201 while (Entry
!= &ptirec
->SentMessagesListHead
)
1203 if (CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
) == Message
)
1205 Message
->pkCompletionEvent
= NULL
;
1206 RemoveEntryList(&Message
->ListEntry
);
1207 ClearMsgBitsMask(ptirec
, Message
->QS_Flags
);
1208 InsertTailList(&usmList
, &Message
->ListEntry
);
1211 Entry
= Entry
->Flink
;
1214 ERR("MsqSendMessage (blocked) timed out 1 Status %lx\n", WaitStatus
);
1216 // Receiving thread passed on and left us hanging with issues still pending.
1217 else if (WaitStatus
== STATUS_WAIT_1
)
1219 ERR("Bk Receiving Thread woken up dead!\n");
1220 Message
->flags
|= SMF_RECEIVERDIED
;
1223 while (co_MsqDispatchOneSentMessage(pti
))
1228 PVOID WaitObjects
[3];
1230 WaitObjects
[0] = Message
->pkCompletionEvent
; // Wait 0
1231 WaitObjects
[1] = pti
->pEventQueueServer
; // Wait 1
1232 WaitObjects
[2] = ptirec
->pEThread
; // Wait 2
1238 WaitStatus
= KeWaitForMultipleObjects( 3,
1244 (uTimeout
? &Timeout
: NULL
),
1249 if (WaitStatus
== STATUS_TIMEOUT
)
1251 /* Look up if the message has not yet been dispatched, if so
1252 make sure it can't pass a result and it must not set the completion event anymore */
1253 Entry
= ptirec
->SentMessagesListHead
.Flink
;
1254 while (Entry
!= &ptirec
->SentMessagesListHead
)
1256 if (CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
) == Message
)
1258 Message
->pkCompletionEvent
= NULL
;
1259 RemoveEntryList(&Message
->ListEntry
);
1260 ClearMsgBitsMask(ptirec
, Message
->QS_Flags
);
1261 InsertTailList(&usmList
, &Message
->ListEntry
);
1264 Entry
= Entry
->Flink
;
1267 ERR("MsqSendMessage timed out 2 Status %lx\n", WaitStatus
);
1270 // Receiving thread passed on and left us hanging with issues still pending.
1271 else if (WaitStatus
== STATUS_WAIT_2
)
1273 ERR("NB Receiving Thread woken up dead!\n");
1274 Message
->flags
|= SMF_RECEIVERDIED
;
1278 if (WaitStatus
== STATUS_USER_APC
) break;
1280 while (co_MsqDispatchOneSentMessage(pti
))
1282 } while (WaitStatus
== STATUS_WAIT_1
);
1285 // Count is nil, restore swapping of the stack.
1286 if (--pti
->cEnterCount
== 0 )
1288 KeSetKernelStackSwapEnable(SwapStateEnabled
);
1292 if (WaitStatus
== STATUS_USER_APC
)
1294 // The current thread is dying!
1295 TRACE("User APC\n");
1297 // The Message will be on the Trouble list until Thread cleanup.
1298 Message
->flags
|= SMF_SENDERDIED
;
1300 co_IntDeliverUserAPC();
1301 ERR("User APC Returned\n"); // Should not see this message.
1304 // Force this thread to wake up for the next go around.
1305 KeSetEvent(pti
->pEventQueueServer
, IO_NO_INCREMENT
, FALSE
);
1307 Result
= Message
->lResult
;
1309 // Determine whether this message is being processed or not.
1310 if ((Message
->flags
& (SMF_RECEIVERBUSY
|SMF_RECEIVEDMESSAGE
)) != SMF_RECEIVEDMESSAGE
)
1312 Message
->flags
|= SMF_RECEIVERFREE
;
1315 if (!(Message
->flags
& SMF_RECEIVERFREE
))
1317 TRACE("Sender Freeing Message %p ptirec %p bit %d list empty %d\n",Message
,ptirec
,!!(ptirec
->pcti
->fsChangeBits
& QS_SENDMESSAGE
),IsListEmpty(&ptirec
->SentMessagesListHead
));
1318 // Make it to this point, the message was received.
1319 FreeUserMessage(Message
);
1322 pti
->pusmSent
= SaveMsg
;
1324 TRACE("MSM Allocation Count %d Status %lx Result %d\n",SendMsgCount
,WaitStatus
,Result
);
1326 if (WaitStatus
!= STATUS_TIMEOUT
)
1330 *uResult
= (STATUS_WAIT_0
== WaitStatus
? Result
: 0);
1338 MsqPostMessage(PTHREADINFO pti
,
1340 BOOLEAN HardwareMessage
,
1345 PUSER_MESSAGE Message
;
1346 PUSER_MESSAGE_QUEUE MessageQueue
;
1348 if ( pti
->TIF_flags
& TIF_INCLEANUP
|| pti
->MessageQueue
->QF_flags
& QF_INDESTROY
)
1350 ERR("Post Msg; Thread or Q is Dead!\n");
1354 if(!(Message
= MsqCreateMessage(Msg
)))
1359 MessageQueue
= pti
->MessageQueue
;
1361 if (!HardwareMessage
)
1363 InsertTailList(&pti
->PostedMessagesListHead
, &Message
->ListEntry
);
1367 InsertTailList(&MessageQueue
->HardwareMessagesListHead
, &Message
->ListEntry
);
1370 if (Msg
->message
== WM_HOTKEY
) MessageBits
|= QS_HOTKEY
; // Justin Case, just set it.
1371 Message
->dwQEvent
= dwQEvent
;
1372 Message
->ExtraInfo
= ExtraInfo
;
1373 Message
->QS_Flags
= MessageBits
;
1375 MsqWakeQueue(pti
, MessageBits
, TRUE
);
1376 TRACE("Post Message %d\n",PostMsgCount
);
1380 MsqPostQuitMessage(PTHREADINFO pti
, ULONG ExitCode
)
1382 pti
->QuitPosted
= TRUE
;
1383 pti
->exitCode
= ExitCode
;
1384 MsqWakeQueue(pti
, QS_POSTMESSAGE
|QS_ALLPOSTMESSAGE
, TRUE
);
1387 /***********************************************************************
1388 * MsqSendParentNotify
1390 * Send a WM_PARENTNOTIFY to all ancestors of the given window, unless
1391 * the window has the WS_EX_NOPARENTNOTIFY style.
1393 static void MsqSendParentNotify( PWND pwnd
, WORD event
, WORD idChild
, POINT pt
)
1395 PWND pwndDesktop
= UserGetDesktopWindow();
1397 /* pt has to be in the client coordinates of the parent window */
1398 pt
.x
+= pwndDesktop
->rcClient
.left
- pwnd
->rcClient
.left
;
1399 pt
.y
+= pwndDesktop
->rcClient
.top
- pwnd
->rcClient
.top
;
1405 if (!(pwnd
->style
& WS_CHILD
)) break;
1406 if (pwnd
->ExStyle
& WS_EX_NOPARENTNOTIFY
) break;
1407 if (!(pwndParent
= IntGetParent(pwnd
))) break;
1408 if (pwndParent
== pwndDesktop
) break;
1409 pt
.x
+= pwnd
->rcClient
.left
- pwndParent
->rcClient
.left
;
1410 pt
.y
+= pwnd
->rcClient
.top
- pwndParent
->rcClient
.top
;
1413 co_IntSendMessage( UserHMGetHandle(pwnd
), WM_PARENTNOTIFY
,
1414 MAKEWPARAM( event
, idChild
), MAKELPARAM( pt
.x
, pt
.y
) );
1420 IntTrackMouseMove(PWND pwndTrack
, PDESKTOP pDesk
, PMSG msg
, USHORT hittest
)
1422 // PWND pwndTrack = IntChildrenWindowFromPoint(pwndMsg, msg->pt.x, msg->pt.y);
1423 // hittest = (USHORT)GetNCHitEx(pwndTrack, msg->pt); /// @todo WTF is this???
1425 if ( pDesk
->spwndTrack
!= pwndTrack
|| // Change with tracking window or
1426 msg
->message
!= WM_MOUSEMOVE
|| // Mouse click changes or
1427 pDesk
->htEx
!= hittest
) // Change in current hit test states.
1429 TRACE("ITMM: Track Mouse Move!\n");
1431 /* Handle only the changing window track and mouse move across a border. */
1432 if ( pDesk
->spwndTrack
!= pwndTrack
||
1433 (pDesk
->htEx
== HTCLIENT
) ^ (hittest
== HTCLIENT
) )
1435 TRACE("ITMM: Another Wnd %d or Across Border %d\n",
1436 pDesk
->spwndTrack
!= pwndTrack
,(pDesk
->htEx
== HTCLIENT
) ^ (hittest
== HTCLIENT
));
1438 if ( pDesk
->dwDTFlags
& DF_TME_LEAVE
)
1439 UserPostMessage( UserHMGetHandle(pDesk
->spwndTrack
),
1440 (pDesk
->htEx
!= HTCLIENT
) ? WM_NCMOUSELEAVE
: WM_MOUSELEAVE
,
1443 if ( pDesk
->dwDTFlags
& DF_TME_HOVER
)
1444 IntKillTimer(pDesk
->spwndTrack
, ID_EVENT_SYSTIMER_MOUSEHOVER
, TRUE
);
1446 /* Clear the flags to sign a change. */
1447 pDesk
->dwDTFlags
&= ~(DF_TME_LEAVE
|DF_TME_HOVER
);
1449 /* Set the Track window and hit test. */
1450 pDesk
->spwndTrack
= pwndTrack
;
1451 pDesk
->htEx
= hittest
;
1454 /* Reset, Same Track window, Hover set and Mouse Clicks or Clobbered Hover box. */
1455 if ( pDesk
->spwndTrack
== pwndTrack
&&
1456 ( msg
->message
!= WM_MOUSEMOVE
|| !RECTL_bPointInRect(&pDesk
->rcMouseHover
, msg
->pt
.x
, msg
->pt
.y
)) &&
1457 pDesk
->dwDTFlags
& DF_TME_HOVER
)
1459 TRACE("ITMM: Reset Hover points!\n");
1460 // Restart timer for the hover period.
1461 IntSetTimer(pDesk
->spwndTrack
, ID_EVENT_SYSTIMER_MOUSEHOVER
, pDesk
->dwMouseHoverTime
, SystemTimerProc
, TMRF_SYSTEM
);
1462 // Reset desktop mouse hover from the system default hover rectangle.
1463 RECTL_vSetRect(&pDesk
->rcMouseHover
,
1464 msg
->pt
.x
- gspv
.iMouseHoverWidth
/ 2,
1465 msg
->pt
.y
- gspv
.iMouseHoverHeight
/ 2,
1466 msg
->pt
.x
+ gspv
.iMouseHoverWidth
/ 2,
1467 msg
->pt
.y
+ gspv
.iMouseHoverHeight
/ 2);
1471 BOOL
co_IntProcessMouseMessage(MSG
* msg
, BOOL
* RemoveMessages
, BOOL
* NotForUs
, LONG_PTR ExtraInfo
, UINT first
, UINT last
)
1478 MOUSEHOOKSTRUCT hook
;
1479 BOOL eatMsg
= FALSE
;
1481 PWND pwndMsg
, pwndDesktop
;
1482 PUSER_MESSAGE_QUEUE MessageQueue
;
1484 PSYSTEM_CURSORINFO CurInfo
;
1487 pti
= PsGetCurrentThreadWin32Thread();
1488 pwndDesktop
= UserGetDesktopWindow();
1489 MessageQueue
= pti
->MessageQueue
;
1490 CurInfo
= IntGetSysCursorInfo();
1491 pwndMsg
= ValidateHwndNoErr(msg
->hwnd
);
1492 clk_msg
= MessageQueue
->msgDblClk
;
1493 pDesk
= pwndDesktop
->head
.rpdesk
;
1495 /* find the window to dispatch this mouse message to */
1496 if (MessageQueue
->spwndCapture
)
1499 pwndMsg
= MessageQueue
->spwndCapture
;
1504 Start with null window. See wine win.c:test_mouse_input:WM_COMMAND tests.
1506 pwndMsg
= co_WinPosWindowFromPoint( NULL
, &msg
->pt
, &hittest
, FALSE
);
1509 TRACE("Got mouse message for %p, hittest: 0x%x\n", msg
->hwnd
, hittest
);
1511 // Null window or not the same "Hardware" message queue.
1512 if (pwndMsg
== NULL
|| pwndMsg
->head
.pti
->MessageQueue
!= MessageQueue
)
1514 // Crossing a boundary, so set cursor. See default message queue cursor.
1515 IntSystemSetCursor(SYSTEMCUR(ARROW
));
1516 /* Remove and ignore the message */
1517 *RemoveMessages
= TRUE
;
1521 // Check to see if this is attached,
1522 if ( pwndMsg
->head
.pti
!= pti
&& // window thread is not current,
1523 MessageQueue
->cThreads
> 1 ) // and is attached...
1525 // This is not for us and we should leave so the other thread can check for messages!!!
1527 *RemoveMessages
= TRUE
;
1531 if ( MessageQueue
== gpqCursor
) // Cursor must use the same Queue!
1533 IntTrackMouseMove(pwndMsg
, pDesk
, msg
, hittest
);
1537 ERR("Not the same cursor!\n");
1540 msg
->hwnd
= UserHMGetHandle(pwndMsg
);
1543 message
= msg
->message
;
1545 /* Note: windows has no concept of a non-client wheel message */
1546 if (message
!= WM_MOUSEWHEEL
)
1548 if (hittest
!= HTCLIENT
)
1550 message
+= WM_NCMOUSEMOVE
- WM_MOUSEMOVE
;
1551 msg
->wParam
= hittest
; // Caution! This might break wParam check in DblClk.
1555 /* coordinates don't get translated while tracking a menu */
1556 /* FIXME: should differentiate popups and top-level menus */
1557 if (!(MessageQueue
->MenuOwner
))
1559 pt
.x
+= pwndDesktop
->rcClient
.left
- pwndMsg
->rcClient
.left
;
1560 pt
.y
+= pwndDesktop
->rcClient
.top
- pwndMsg
->rcClient
.top
;
1564 msg
->lParam
= MAKELONG( pt
.x
, pt
.y
);
1566 /* translate double clicks */
1568 if ((msg
->message
== WM_LBUTTONDOWN
) ||
1569 (msg
->message
== WM_RBUTTONDOWN
) ||
1570 (msg
->message
== WM_MBUTTONDOWN
) ||
1571 (msg
->message
== WM_XBUTTONDOWN
))
1573 BOOL update
= *RemoveMessages
;
1575 /* translate double clicks -
1576 * note that ...MOUSEMOVEs can slip in between
1577 * ...BUTTONDOWN and ...BUTTONDBLCLK messages */
1579 if ((MessageQueue
->MenuOwner
|| MessageQueue
->MoveSize
) ||
1580 hittest
!= HTCLIENT
||
1581 (pwndMsg
->pcls
->style
& CS_DBLCLKS
))
1583 if ((msg
->message
== clk_msg
.message
) &&
1584 (msg
->hwnd
== clk_msg
.hwnd
) &&
1585 // Only worry about XButton wParam.
1586 (msg
->message
!= WM_XBUTTONDOWN
|| GET_XBUTTON_WPARAM(msg
->wParam
) == GET_XBUTTON_WPARAM(clk_msg
.wParam
)) &&
1587 ((msg
->time
- clk_msg
.time
) < (ULONG
)gspv
.iDblClickTime
) &&
1588 (abs(msg
->pt
.x
- clk_msg
.pt
.x
) < UserGetSystemMetrics(SM_CXDOUBLECLK
)/2) &&
1589 (abs(msg
->pt
.y
- clk_msg
.pt
.y
) < UserGetSystemMetrics(SM_CYDOUBLECLK
)/2))
1591 message
+= (WM_LBUTTONDBLCLK
- WM_LBUTTONDOWN
);
1594 MessageQueue
->msgDblClk
.message
= 0; /* clear the double click conditions */
1600 if (!((first
== 0 && last
== 0) || (message
>= first
|| message
<= last
)))
1602 TRACE("Message out of range!!!\n");
1606 /* update static double click conditions */
1607 if (update
) MessageQueue
->msgDblClk
= *msg
;
1611 if (!((first
== 0 && last
== 0) || (message
>= first
|| message
<= last
)))
1613 TRACE("Message out of range!!!\n");
1617 // Update mouse move down keys.
1618 if (message
== WM_MOUSEMOVE
)
1620 msg
->wParam
= MsqGetDownKeyState(MessageQueue
);
1624 if (gspv
.bMouseClickLock
)
1626 BOOL IsClkLck
= FALSE
;
1628 if(msg
->message
== WM_LBUTTONUP
)
1630 IsClkLck
= ((msg
->time
- CurInfo
->ClickLockTime
) >= gspv
.dwMouseClickLockTime
);
1631 if (IsClkLck
&& (!CurInfo
->ClickLockActive
))
1633 CurInfo
->ClickLockActive
= TRUE
;
1636 else if (msg
->message
== WM_LBUTTONDOWN
)
1638 if (CurInfo
->ClickLockActive
)
1641 CurInfo
->ClickLockActive
= FALSE
;
1644 CurInfo
->ClickLockTime
= msg
->time
;
1649 /* Remove and ignore the message */
1650 *RemoveMessages
= TRUE
;
1651 TRACE("Remove and ignore the message\n");
1656 if (pti
->TIF_flags
& TIF_MSGPOSCHANGED
)
1658 pti
->TIF_flags
&= ~TIF_MSGPOSCHANGED
;
1659 IntNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE
, NULL
, OBJID_CLIENT
, CHILDID_SELF
, 0);
1662 /* message is accepted now (but still get dropped) */
1664 event
.message
= msg
->message
;
1665 event
.time
= msg
->time
;
1666 event
.hwnd
= msg
->hwnd
;
1667 event
.paramL
= msg
->pt
.x
;
1668 event
.paramH
= msg
->pt
.y
;
1669 co_HOOK_CallHooks( WH_JOURNALRECORD
, HC_ACTION
, 0, (LPARAM
)&event
);
1672 hook
.hwnd
= msg
->hwnd
;
1673 hook
.wHitTestCode
= hittest
;
1674 hook
.dwExtraInfo
= ExtraInfo
;
1675 if (co_HOOK_CallHooks( WH_MOUSE
, *RemoveMessages
? HC_ACTION
: HC_NOREMOVE
,
1676 message
, (LPARAM
)&hook
))
1679 hook
.hwnd
= msg
->hwnd
;
1680 hook
.wHitTestCode
= hittest
;
1681 hook
.dwExtraInfo
= ExtraInfo
;
1682 co_HOOK_CallHooks( WH_CBT
, HCBT_CLICKSKIPPED
, message
, (LPARAM
)&hook
);
1684 ERR("WH_MOUSE dropped mouse message!\n");
1686 /* Remove and skip message */
1687 *RemoveMessages
= TRUE
;
1691 if ((hittest
== (USHORT
)HTERROR
) || (hittest
== (USHORT
)HTNOWHERE
))
1693 co_IntSendMessage( msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)msg
->hwnd
, MAKELONG( hittest
, msg
->message
));
1695 /* Remove and skip message */
1696 *RemoveMessages
= TRUE
;
1700 if ((*RemoveMessages
== FALSE
) || MessageQueue
->spwndCapture
)
1702 /* Accept the message */
1703 msg
->message
= message
;
1707 if ((msg
->message
== WM_LBUTTONDOWN
) ||
1708 (msg
->message
== WM_RBUTTONDOWN
) ||
1709 (msg
->message
== WM_MBUTTONDOWN
) ||
1710 (msg
->message
== WM_XBUTTONDOWN
))
1712 /* Send the WM_PARENTNOTIFY,
1713 * note that even for double/nonclient clicks
1714 * notification message is still WM_L/M/RBUTTONDOWN.
1716 MsqSendParentNotify(pwndMsg
, msg
->message
, 0, msg
->pt
);
1718 /* Activate the window if needed */
1720 if (pwndMsg
!= MessageQueue
->spwndActive
)
1722 PWND pwndTop
= pwndMsg
;
1723 pwndTop
= IntGetNonChildAncestor(pwndTop
);
1725 TRACE("Mouse pti %p pwndMsg pti %p pwndTop pti %p\n",MessageQueue
->ptiMouse
,pwndMsg
->head
.pti
,pwndTop
->head
.pti
);
1727 if (pwndTop
&& pwndTop
!= pwndDesktop
)
1729 LONG ret
= co_IntSendMessage( msg
->hwnd
,
1731 (WPARAM
)UserHMGetHandle(pwndTop
),
1732 MAKELONG( hittest
, msg
->message
));
1735 case MA_NOACTIVATEANDEAT
:
1740 case MA_ACTIVATEANDEAT
:
1745 if (!co_IntMouseActivateWindow( pwndTop
)) eatMsg
= TRUE
;
1748 ERR( "unknown WM_MOUSEACTIVATE code %d\n", ret
);
1755 /* send the WM_SETCURSOR message */
1757 /* Windows sends the normal mouse message as the message parameter
1758 in the WM_SETCURSOR message even if it's non-client mouse message */
1759 co_IntSendMessage( msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)msg
->hwnd
, MAKELONG( hittest
, msg
->message
));
1761 msg
->message
= message
;
1765 BOOL
co_IntProcessKeyboardMessage(MSG
* Msg
, BOOL
* RemoveMessages
)
1768 USER_REFERENCE_ENTRY Ref
;
1772 WPARAM wParam
= Msg
->wParam
;
1773 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
1775 if (Msg
->message
== VK_PACKET
)
1777 pti
->wchInjected
= HIWORD(Msg
->wParam
);
1780 if (Msg
->message
== WM_KEYDOWN
|| Msg
->message
== WM_SYSKEYDOWN
||
1781 Msg
->message
== WM_KEYUP
|| Msg
->message
== WM_SYSKEYUP
)
1783 switch (Msg
->wParam
)
1785 case VK_LSHIFT
: case VK_RSHIFT
:
1786 Msg
->wParam
= VK_SHIFT
;
1788 case VK_LCONTROL
: case VK_RCONTROL
:
1789 Msg
->wParam
= VK_CONTROL
;
1791 case VK_LMENU
: case VK_RMENU
:
1792 Msg
->wParam
= VK_MENU
;
1797 pWnd
= ValidateHwndNoErr(Msg
->hwnd
);
1798 if (pWnd
) UserRefObjectCo(pWnd
, &Ref
);
1800 Event
.message
= Msg
->message
;
1801 Event
.hwnd
= Msg
->hwnd
;
1802 Event
.time
= Msg
->time
;
1803 Event
.paramL
= (Msg
->wParam
& 0xFF) | (HIWORD(Msg
->lParam
) << 8);
1804 Event
.paramH
= Msg
->lParam
& 0x7FFF;
1805 if (HIWORD(Msg
->lParam
) & 0x0100) Event
.paramH
|= 0x8000;
1806 co_HOOK_CallHooks( WH_JOURNALRECORD
, HC_ACTION
, 0, (LPARAM
)&Event
);
1808 if (*RemoveMessages
)
1810 if ((Msg
->message
== WM_KEYDOWN
) &&
1811 (Msg
->hwnd
!= IntGetDesktopWindow()))
1813 /* Handle F1 key by sending out WM_HELP message */
1814 if (Msg
->wParam
== VK_F1
)
1816 UserPostMessage( Msg
->hwnd
, WM_KEYF1
, 0, 0 );
1818 else if (Msg
->wParam
>= VK_BROWSER_BACK
&&
1819 Msg
->wParam
<= VK_LAUNCH_APP2
)
1821 /* FIXME: Process keystate */
1822 co_IntSendMessage(Msg
->hwnd
, WM_APPCOMMAND
, (WPARAM
)Msg
->hwnd
, MAKELPARAM(0, (FAPPCOMMAND_KEY
| (Msg
->wParam
- VK_BROWSER_BACK
+ 1))));
1825 else if (Msg
->message
== WM_KEYUP
)
1827 /* Handle VK_APPS key by posting a WM_CONTEXTMENU message */
1828 if (Msg
->wParam
== VK_APPS
&& pti
->MessageQueue
->MenuOwner
== NULL
)
1829 UserPostMessage( Msg
->hwnd
, WM_CONTEXTMENU
, (WPARAM
)Msg
->hwnd
, -1 );
1834 if ( *RemoveMessages
&& Msg
->message
== WM_SYSKEYDOWN
)
1836 if ( HIWORD(Msg
->lParam
) & KF_ALTDOWN
)
1838 if ( Msg
->wParam
== VK_ESCAPE
|| Msg
->wParam
== VK_TAB
) // Alt-Tab/ESC Alt-Shift-Tab/ESC
1842 wParamTmp
= UserGetKeyState(VK_SHIFT
) & 0x8000 ? SC_PREVWINDOW
: SC_NEXTWINDOW
;
1843 TRACE("Send WM_SYSCOMMAND Alt-Tab/ESC Alt-Shift-Tab/ESC\n");
1844 co_IntSendMessage( Msg
->hwnd
, WM_SYSCOMMAND
, wParamTmp
, Msg
->wParam
);
1854 if ( *RemoveMessages
&& (Msg
->message
== WM_SYSKEYDOWN
|| Msg
->message
== WM_KEYDOWN
) )
1856 if (gdwLanguageToggleKey
< 3)
1858 if (IS_KEY_DOWN(gafAsyncKeyState
, gdwLanguageToggleKey
== 1 ? VK_LMENU
: VK_CONTROL
)) // L Alt 1 or Ctrl 2 .
1860 if ( wParam
== VK_LSHIFT
) gLanguageToggleKeyState
= INPUTLANGCHANGE_FORWARD
; // Left Alt - Left Shift, Next
1861 //// FIXME : It seems to always be VK_LSHIFT.
1862 if ( wParam
== VK_RSHIFT
) gLanguageToggleKeyState
= INPUTLANGCHANGE_BACKWARD
; // Left Alt - Right Shift, Previous
1867 //// Key Up! Alt Key Ctrl Key
1868 if ( *RemoveMessages
&& (Msg
->message
== WM_SYSKEYUP
|| Msg
->message
== WM_KEYUP
) )
1870 // When initializing win32k: Reading from the registry hotkey combination
1871 // to switch the keyboard layout and store it to global variable.
1872 // Using this combination of hotkeys in this function
1874 if ( gdwLanguageToggleKey
< 3 &&
1875 IS_KEY_DOWN(gafAsyncKeyState
, gdwLanguageToggleKey
== 1 ? VK_LMENU
: VK_CONTROL
) )
1877 if ( Msg
->wParam
== VK_SHIFT
&& !(IS_KEY_DOWN(gafAsyncKeyState
, VK_SHIFT
)))
1880 PKL pkl
= pti
->KeyboardLayout
;
1882 if (pWnd
) UserDerefObjectCo(pWnd
);
1884 //// Seems to override message window.
1885 if (!(pWnd
= pti
->MessageQueue
->spwndFocus
))
1887 pWnd
= pti
->MessageQueue
->spwndActive
;
1889 if (pWnd
) UserRefObjectCo(pWnd
, &Ref
);
1891 if (pkl
!= NULL
&& gLanguageToggleKeyState
)
1893 TRACE("Posting WM_INPUTLANGCHANGEREQUEST KeyState %d\n", gLanguageToggleKeyState
);
1895 wParamILR
= gLanguageToggleKeyState
;
1896 // If system character set and font signature send flag.
1897 if ( gSystemFS
& pkl
->dwFontSigs
)
1899 wParamILR
|= INPUTLANGCHANGE_SYSCHARSET
;
1902 UserPostMessage( UserHMGetHandle(pWnd
),
1903 WM_INPUTLANGCHANGEREQUEST
,
1907 gLanguageToggleKeyState
= 0;
1917 if (co_HOOK_CallHooks( WH_KEYBOARD
,
1918 *RemoveMessages
? HC_ACTION
: HC_NOREMOVE
,
1919 LOWORD(Msg
->wParam
),
1922 /* skip this message */
1923 co_HOOK_CallHooks( WH_CBT
,
1925 LOWORD(Msg
->wParam
),
1928 ERR("KeyboardMessage WH_KEYBOARD Call Hook return!\n");
1930 *RemoveMessages
= TRUE
;
1935 if ( pWnd
&& Ret
&& *RemoveMessages
&& Msg
->message
== WM_KEYDOWN
&& !(pti
->TIF_flags
& TIF_DISABLEIME
))
1937 if ( (ImmRet
= IntImmProcessKey(pti
->MessageQueue
, pWnd
, Msg
->message
, Msg
->wParam
, Msg
->lParam
)) )
1939 if ( ImmRet
& (IPHK_HOTKEY
|IPHK_SKIPTHISKEY
) )
1943 if ( ImmRet
& IPHK_PROCESSBYIME
)
1945 Msg
->wParam
= VK_PROCESSKEY
;
1950 if (pWnd
) UserDerefObjectCo(pWnd
);
1954 BOOL
co_IntProcessHardwareMessage(MSG
* Msg
, BOOL
* RemoveMessages
, BOOL
* NotForUs
, LONG_PTR ExtraInfo
, UINT first
, UINT last
)
1956 if ( IS_MOUSE_MESSAGE(Msg
->message
))
1958 return co_IntProcessMouseMessage(Msg
, RemoveMessages
, NotForUs
, ExtraInfo
, first
, last
);
1960 else if ( IS_KBD_MESSAGE(Msg
->message
))
1962 return co_IntProcessKeyboardMessage(Msg
, RemoveMessages
);
1968 /* check whether a message filter contains at least one potential hardware message */
1970 filter_contains_hw_range( UINT first
, UINT last
)
1972 /* hardware message ranges are (in numerical order):
1973 * WM_NCMOUSEFIRST .. WM_NCMOUSELAST
1974 * WM_KEYFIRST .. WM_KEYLAST
1975 * WM_MOUSEFIRST .. WM_MOUSELAST
1978 if (last
< WM_NCMOUSEFIRST
) return 0;
1979 if (first
> WM_NCMOUSELAST
&& last
< WM_KEYFIRST
) return 0;
1980 if (first
> WM_KEYLAST
&& last
< WM_MOUSEFIRST
) return 0;
1981 if (first
> WM_MOUSELAST
) return 0;
1985 /* check whether message is in the range of mouse messages */
1986 static inline BOOL
is_mouse_message( UINT message
)
1988 return ( //( message >= WM_NCMOUSEFIRST && message <= WM_NCMOUSELAST ) || This seems to break tests...
1989 ( message
>= WM_MOUSEFIRST
&& message
<= WM_MOUSELAST
) ||
1990 ( message
>= WM_XBUTTONDOWN
&& message
<= WM_XBUTTONDBLCLK
) ||
1991 ( message
>= WM_MBUTTONDOWN
&& message
<= WM_MBUTTONDBLCLK
) ||
1992 ( message
>= WM_LBUTTONDOWN
&& message
<= WM_RBUTTONDBLCLK
) );
1996 co_MsqPeekHardwareMessage(IN PTHREADINFO pti
,
1999 IN UINT MsgFilterLow
,
2000 IN UINT MsgFilterHigh
,
2004 BOOL AcceptMessage
, NotForUs
;
2005 PUSER_MESSAGE CurrentMessage
;
2006 PLIST_ENTRY ListHead
;
2012 PUSER_MESSAGE_QUEUE MessageQueue
= pti
->MessageQueue
;
2014 if (!filter_contains_hw_range( MsgFilterLow
, MsgFilterHigh
)) return FALSE
;
2016 ListHead
= MessageQueue
->HardwareMessagesListHead
.Flink
;
2018 if (IsListEmpty(ListHead
)) return FALSE
;
2020 if (!MessageQueue
->ptiSysLock
)
2022 MessageQueue
->ptiSysLock
= pti
;
2023 pti
->pcti
->CTI_flags
|= CTI_THREADSYSLOCK
;
2026 if (MessageQueue
->ptiSysLock
!= pti
)
2028 ERR("Thread Q is locked to ptiSysLock 0x%p pti 0x%p\n",MessageQueue
->ptiSysLock
,pti
);
2032 while (ListHead
!= &MessageQueue
->HardwareMessagesListHead
)
2034 CurrentMessage
= CONTAINING_RECORD(ListHead
, USER_MESSAGE
, ListEntry
);
2035 ListHead
= ListHead
->Flink
;
2037 if (MessageQueue
->idSysPeek
== (ULONG_PTR
)CurrentMessage
)
2039 TRACE("Skip this message due to it is in play!\n");
2044 1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL.
2045 2: retrieves only messages on the current thread's message queue whose hwnd value is NULL.
2046 3: handle to the window whose messages are to be retrieved.
2048 if ( ( !Window
|| // 1
2049 ( Window
== PWND_BOTTOM
&& CurrentMessage
->Msg
.hwnd
== NULL
) || // 2
2050 ( Window
!= PWND_BOTTOM
&& Window
->head
.h
== CurrentMessage
->Msg
.hwnd
) || // 3
2051 ( is_mouse_message(CurrentMessage
->Msg
.message
) ) ) && // Null window for anything mouse.
2052 ( ( ( MsgFilterLow
== 0 && MsgFilterHigh
== 0 ) && CurrentMessage
->QS_Flags
& QSflags
) ||
2053 ( MsgFilterLow
<= CurrentMessage
->Msg
.message
&& MsgFilterHigh
>= CurrentMessage
->Msg
.message
) ) )
2055 idSave
= MessageQueue
->idSysPeek
;
2056 MessageQueue
->idSysPeek
= (ULONG_PTR
)CurrentMessage
;
2058 msg
= CurrentMessage
->Msg
;
2059 ExtraInfo
= CurrentMessage
->ExtraInfo
;
2060 QS_Flags
= CurrentMessage
->QS_Flags
;
2064 UpdateKeyStateFromMsg(MessageQueue
, &msg
);
2065 AcceptMessage
= co_IntProcessHardwareMessage(&msg
, &Remove
, &NotForUs
, ExtraInfo
, MsgFilterLow
, MsgFilterHigh
);
2069 if (CurrentMessage
->pti
!= NULL
&& (MessageQueue
->idSysPeek
== (ULONG_PTR
)CurrentMessage
))
2071 MsqDestroyMessage(CurrentMessage
);
2073 ClearMsgBitsMask(pti
, QS_Flags
);
2076 MessageQueue
->idSysPeek
= idSave
;
2087 // Fix all but one wine win:test_GetMessagePos WM_TIMER tests. See PostTimerMessages.
2088 if (!RtlEqualMemory(&pti
->ptLast
, &msg
.pt
, sizeof(POINT
)))
2090 pti
->TIF_flags
|= TIF_MSGPOSCHANGED
;
2092 pti
->timeLast
= msg
.time
;
2093 pti
->ptLast
= msg
.pt
;
2094 MessageQueue
->ExtraInfo
= ExtraInfo
;
2101 MessageQueue
->ptiSysLock
= NULL
;
2102 pti
->pcti
->CTI_flags
&= ~CTI_THREADSYSLOCK
;
2107 MsqPeekMessage(IN PTHREADINFO pti
,
2110 IN UINT MsgFilterLow
,
2111 IN UINT MsgFilterHigh
,
2113 OUT LONG_PTR
*ExtraInfo
,
2114 OUT DWORD
*dwQEvent
,
2117 PUSER_MESSAGE CurrentMessage
;
2118 PLIST_ENTRY ListHead
;
2122 ListHead
= pti
->PostedMessagesListHead
.Flink
;
2124 if (IsListEmpty(ListHead
)) return FALSE
;
2126 while(ListHead
!= &pti
->PostedMessagesListHead
)
2128 CurrentMessage
= CONTAINING_RECORD(ListHead
, USER_MESSAGE
, ListEntry
);
2129 ListHead
= ListHead
->Flink
;
2132 1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL.
2133 2: retrieves only messages on the current thread's message queue whose hwnd value is NULL.
2134 3: handle to the window whose messages are to be retrieved.
2136 if ( ( !Window
|| // 1
2137 ( Window
== PWND_BOTTOM
&& CurrentMessage
->Msg
.hwnd
== NULL
) || // 2
2138 ( Window
!= PWND_BOTTOM
&& Window
->head
.h
== CurrentMessage
->Msg
.hwnd
) ) && // 3
2139 ( ( ( MsgFilterLow
== 0 && MsgFilterHigh
== 0 ) && CurrentMessage
->QS_Flags
& QSflags
) ||
2140 ( MsgFilterLow
<= CurrentMessage
->Msg
.message
&& MsgFilterHigh
>= CurrentMessage
->Msg
.message
) ) )
2142 *Message
= CurrentMessage
->Msg
;
2143 *ExtraInfo
= CurrentMessage
->ExtraInfo
;
2144 QS_Flags
= CurrentMessage
->QS_Flags
;
2145 if (dwQEvent
) *dwQEvent
= CurrentMessage
->dwQEvent
;
2149 if (CurrentMessage
->pti
!= NULL
)
2151 MsqDestroyMessage(CurrentMessage
);
2153 ClearMsgBitsMask(pti
, QS_Flags
);
2164 co_MsqWaitForNewMessages(PTHREADINFO pti
, PWND WndFilter
,
2165 UINT MsgFilterMin
, UINT MsgFilterMax
)
2167 NTSTATUS ret
= STATUS_SUCCESS
;
2169 // Post mouse moves before waiting for messages.
2170 if (pti
->MessageQueue
->QF_flags
& QF_MOUSEMOVED
)
2172 IntCoalesceMouseMove(pti
);
2177 ZwYieldExecution(); // Let someone else run!
2179 ret
= KeWaitForSingleObject( pti
->pEventQueueServer
,
2185 if ( ret
== STATUS_USER_APC
)
2187 TRACE("MWFNW User APC\n");
2188 co_IntDeliverUserAPC();
2194 MsqIsHung(PTHREADINFO pti
, DWORD TimeOut
)
2196 DWORD dwTimeStamp
= EngGetTickCount32();
2197 if (dwTimeStamp
- pti
->pcti
->timeLastRead
> TimeOut
&&
2198 !(pti
->pcti
->fsWakeMask
& QS_INPUT
) &&
2199 !PsGetThreadFreezeCount(pti
->pEThread
) &&
2200 !(pti
->ppi
->W32PF_flags
& W32PF_APPSTARTING
))
2202 TRACE("\nMsqIsHung(pti %p, TimeOut %lu)\n"
2203 "pEThread %p, ThreadsProcess %p, ImageFileName '%s'\n"
2204 "dwTimeStamp = %lu\n"
2205 "pti->pcti->timeLastRead = %lu\n"
2206 "pti->timeLast = %lu\n"
2207 "PsGetThreadFreezeCount(pti->pEThread) = %lu\n",
2210 pti
->pEThread
? pti
->pEThread
->ThreadsProcess
: NULL
,
2211 (pti
->pEThread
&& pti
->pEThread
->ThreadsProcess
)
2212 ? pti
->pEThread
->ThreadsProcess
->ImageFileName
: "(None)",
2214 pti
->pcti
->timeLastRead
,
2216 PsGetThreadFreezeCount(pti
->pEThread
));
2225 IsThreadSuspended(PTHREADINFO pti
)
2230 if (!(pti
->pEThread
->Tcb
.SuspendCount
) && !PsGetThreadFreezeCount(pti
->pEThread
)) Ret
= FALSE
;
2238 HungAppSysTimerProc(HWND hwnd
, UINT uMsg
, UINT_PTR idEvent
, DWORD dwTime
)
2241 TRACE("HungAppSysTimerProc\n");
2242 // Process list of windows that are hung and waiting.
2246 MsqInitializeMessageQueue(PTHREADINFO pti
, PUSER_MESSAGE_QUEUE MessageQueue
)
2248 InitializeListHead(&MessageQueue
->HardwareMessagesListHead
); // Keep here!
2249 MessageQueue
->spwndFocus
= NULL
;
2250 MessageQueue
->iCursorLevel
= 0;
2251 MessageQueue
->CursorObject
= SYSTEMCUR(WAIT
); // See test_initial_cursor.
2252 if (MessageQueue
->CursorObject
)
2254 TRACE("Default cursor hcur %p\n",UserHMGetHandle(MessageQueue
->CursorObject
));
2255 UserReferenceObject(MessageQueue
->CursorObject
);
2257 RtlCopyMemory(MessageQueue
->afKeyState
, gafAsyncKeyState
, sizeof(gafAsyncKeyState
));
2258 MessageQueue
->ptiMouse
= pti
;
2259 MessageQueue
->ptiKeyboard
= pti
;
2260 MessageQueue
->cThreads
++;
2266 MsqCleanupThreadMsgs(PTHREADINFO pti
)
2268 PLIST_ENTRY CurrentEntry
;
2269 PUSER_MESSAGE CurrentMessage
;
2270 PUSER_SENT_MESSAGE CurrentSentMessage
;
2272 TRACE("MsqCleanupThreadMsgs %p\n",pti
);
2274 // Clear it all out.
2277 pti
->pcti
->fsWakeBits
= 0;
2278 pti
->pcti
->fsChangeBits
= 0;
2281 pti
->nCntsQBits
[QSRosKey
] = 0;
2282 pti
->nCntsQBits
[QSRosMouseMove
] = 0;
2283 pti
->nCntsQBits
[QSRosMouseButton
] = 0;
2284 pti
->nCntsQBits
[QSRosPostMessage
] = 0;
2285 pti
->nCntsQBits
[QSRosSendMessage
] = 0;
2286 pti
->nCntsQBits
[QSRosHotKey
] = 0;
2287 pti
->nCntsQBits
[QSRosEvent
] = 0;
2289 /* cleanup posted messages */
2290 while (!IsListEmpty(&pti
->PostedMessagesListHead
))
2292 CurrentEntry
= pti
->PostedMessagesListHead
.Flink
;
2293 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
, ListEntry
);
2294 ERR("Thread Cleanup Post Messages %p\n",CurrentMessage
);
2295 if (CurrentMessage
->dwQEvent
)
2297 if (CurrentMessage
->dwQEvent
== POSTEVENT_NWE
)
2299 ExFreePoolWithTag( (PVOID
)CurrentMessage
->ExtraInfo
, TAG_HOOK
);
2302 MsqDestroyMessage(CurrentMessage
);
2305 /* remove the messages that have not yet been dispatched */
2306 while (!IsListEmpty(&pti
->SentMessagesListHead
))
2308 CurrentEntry
= pti
->SentMessagesListHead
.Flink
;
2309 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
, ListEntry
);
2311 ERR("Thread Cleanup Sent Messages %p\n",CurrentSentMessage
);
2313 /* wake the sender's thread */
2314 if (CurrentSentMessage
->pkCompletionEvent
!= NULL
)
2316 KeSetEvent(CurrentSentMessage
->pkCompletionEvent
, IO_NO_INCREMENT
, FALSE
);
2319 if (CurrentSentMessage
->HasPackedLParam
)
2321 if (CurrentSentMessage
->Msg
.lParam
)
2322 ExFreePool((PVOID
)CurrentSentMessage
->Msg
.lParam
);
2325 /* free the message */
2326 FreeUserMessage(CurrentSentMessage
);
2329 // Process Trouble Message List
2330 if (!IsListEmpty(&usmList
))
2332 CurrentEntry
= usmList
.Flink
;
2333 while (CurrentEntry
!= &usmList
)
2335 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
, ListEntry
);
2336 CurrentEntry
= CurrentEntry
->Flink
;
2338 TRACE("Found troubled messages %p on the list\n",CurrentSentMessage
);
2340 if ( pti
== CurrentSentMessage
->ptiReceiver
)
2342 if (CurrentSentMessage
->HasPackedLParam
)
2344 if (CurrentSentMessage
->Msg
.lParam
)
2345 ExFreePool((PVOID
)CurrentSentMessage
->Msg
.lParam
);
2348 /* free the message */
2349 FreeUserMessage(CurrentSentMessage
);
2351 else if ( pti
== CurrentSentMessage
->ptiSender
||
2352 pti
== CurrentSentMessage
->ptiCallBackSender
)
2354 // Determine whether this message is being processed or not.
2355 if ((CurrentSentMessage
->flags
& (SMF_RECEIVERBUSY
|SMF_RECEIVEDMESSAGE
)) != SMF_RECEIVEDMESSAGE
)
2357 CurrentSentMessage
->flags
|= SMF_RECEIVERFREE
;
2360 if (!(CurrentSentMessage
->flags
& SMF_RECEIVERFREE
))
2363 if (CurrentSentMessage
->HasPackedLParam
)
2365 if (CurrentSentMessage
->Msg
.lParam
)
2366 ExFreePool((PVOID
)CurrentSentMessage
->Msg
.lParam
);
2369 /* free the message */
2370 FreeUserMessage(CurrentSentMessage
);
2378 MsqCleanupMessageQueue(PTHREADINFO pti
)
2380 PUSER_MESSAGE_QUEUE MessageQueue
;
2381 PLIST_ENTRY CurrentEntry
;
2382 PUSER_MESSAGE CurrentMessage
;
2384 MessageQueue
= pti
->MessageQueue
;
2385 MessageQueue
->cThreads
--;
2387 if (MessageQueue
->cThreads
)
2389 if (MessageQueue
->ptiSysLock
== pti
) MessageQueue
->ptiSysLock
= NULL
;
2392 if (MessageQueue
->cThreads
== 0) //// Fix a crash related to CORE-10471 testing.
2394 /* cleanup posted messages */
2395 while (!IsListEmpty(&MessageQueue
->HardwareMessagesListHead
))
2397 CurrentEntry
= MessageQueue
->HardwareMessagesListHead
.Flink
;
2398 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
, ListEntry
);
2399 ERR("MQ Cleanup Post Messages %p\n",CurrentMessage
);
2400 MsqDestroyMessage(CurrentMessage
);
2404 if (MessageQueue
->CursorObject
)
2406 PCURICON_OBJECT pCursor
= MessageQueue
->CursorObject
;
2408 /* Change to another cursor if we going to dereference current one
2409 Note: we can't use UserSetCursor because it uses current thread
2410 message queue instead of queue given for cleanup */
2411 if (IntGetSysCursorInfo()->CurrentCursorObject
== pCursor
)
2415 /* Get the screen DC */
2416 hdcScreen
= IntGetScreenDC();
2418 GreMovePointer(hdcScreen
, -1, -1);
2419 IntGetSysCursorInfo()->CurrentCursorObject
= NULL
;
2422 TRACE("DereferenceObject pCursor\n");
2423 UserDereferenceObject(pCursor
);
2426 if (gpqForeground
== MessageQueue
)
2428 IntSetFocusMessageQueue(NULL
);
2430 if (gpqForegroundPrev
== MessageQueue
)
2432 gpqForegroundPrev
= NULL
;
2434 if (gpqCursor
== MessageQueue
)
2440 PUSER_MESSAGE_QUEUE FASTCALL
2441 MsqCreateMessageQueue(PTHREADINFO pti
)
2443 PUSER_MESSAGE_QUEUE MessageQueue
;
2445 MessageQueue
= ExAllocatePoolWithTag(NonPagedPool
,
2446 sizeof(*MessageQueue
),
2454 RtlZeroMemory(MessageQueue
, sizeof(*MessageQueue
));
2455 /* hold at least one reference until it'll be destroyed */
2456 IntReferenceMessageQueue(MessageQueue
);
2457 /* initialize the queue */
2458 if (!MsqInitializeMessageQueue(pti
, MessageQueue
))
2460 IntDereferenceMessageQueue(MessageQueue
);
2464 return MessageQueue
;
2468 MsqDestroyMessageQueue(_In_ PTHREADINFO pti
)
2471 PUSER_MESSAGE_QUEUE MessageQueue
= pti
->MessageQueue
;
2473 NT_ASSERT(MessageQueue
!= NULL
);
2474 MessageQueue
->QF_flags
|= QF_INDESTROY
;
2476 /* remove the message queue from any desktops */
2477 if ((desk
= InterlockedExchangePointer((PVOID
*)&MessageQueue
->Desktop
, 0)))
2479 (void)InterlockedExchangePointer((PVOID
*)&desk
->ActiveMessageQueue
, 0);
2480 IntDereferenceMessageQueue(MessageQueue
);
2484 MsqCleanupMessageQueue(pti
);
2486 /* decrease the reference counter, if it hits zero, the queue will be freed */
2487 _PRAGMA_WARNING_SUPPRESS(__WARNING_USING_UNINIT_VAR
);
2488 IntDereferenceMessageQueue(MessageQueue
);
2492 MsqSetMessageExtraInfo(LPARAM lParam
)
2496 PUSER_MESSAGE_QUEUE MessageQueue
;
2498 pti
= PsGetCurrentThreadWin32Thread();
2499 MessageQueue
= pti
->MessageQueue
;
2505 Ret
= MessageQueue
->ExtraInfo
;
2506 MessageQueue
->ExtraInfo
= lParam
;
2512 MsqGetMessageExtraInfo(VOID
)
2515 PUSER_MESSAGE_QUEUE MessageQueue
;
2517 pti
= PsGetCurrentThreadWin32Thread();
2518 MessageQueue
= pti
->MessageQueue
;
2524 return MessageQueue
->ExtraInfo
;
2527 // ReplyMessage is called by the thread receiving the window message.
2529 co_MsqReplyMessage( LRESULT lResult
)
2531 PUSER_SENT_MESSAGE Message
;
2534 pti
= PsGetCurrentThreadWin32Thread();
2535 Message
= pti
->pusmCurrent
;
2537 if (!Message
) return FALSE
;
2539 if (Message
->QS_Flags
& QS_SMRESULT
) return FALSE
;
2541 // SendMessageXxx || Callback msg and not a notify msg
2542 if (Message
->ptiSender
|| Message
->CompletionCallback
)
2544 Message
->lResult
= lResult
;
2545 Message
->QS_Flags
|= QS_SMRESULT
;
2546 // See co_MsqDispatchOneSentMessage, change bits already accounted for and cleared and this msg is going away..
2552 MsqSetStateWindow(PTHREADINFO pti
, ULONG Type
, HWND hWnd
)
2555 PUSER_MESSAGE_QUEUE MessageQueue
;
2557 MessageQueue
= pti
->MessageQueue
;
2561 case MSQ_STATE_CAPTURE
:
2562 Prev
= MessageQueue
->spwndCapture
? UserHMGetHandle(MessageQueue
->spwndCapture
) : 0;
2563 MessageQueue
->spwndCapture
= ValidateHwndNoErr(hWnd
);
2565 case MSQ_STATE_ACTIVE
:
2566 Prev
= MessageQueue
->spwndActive
? UserHMGetHandle(MessageQueue
->spwndActive
) : 0;
2567 MessageQueue
->spwndActive
= ValidateHwndNoErr(hWnd
);
2569 case MSQ_STATE_FOCUS
:
2570 Prev
= MessageQueue
->spwndFocus
? UserHMGetHandle(MessageQueue
->spwndFocus
) : 0;
2571 MessageQueue
->spwndFocus
= ValidateHwndNoErr(hWnd
);
2573 case MSQ_STATE_MENUOWNER
:
2574 Prev
= MessageQueue
->MenuOwner
;
2575 MessageQueue
->MenuOwner
= hWnd
;
2577 case MSQ_STATE_MOVESIZE
:
2578 Prev
= MessageQueue
->MoveSize
;
2579 MessageQueue
->MoveSize
= hWnd
;
2581 case MSQ_STATE_CARET
:
2582 Prev
= MessageQueue
->CaretInfo
.hWnd
;
2583 MessageQueue
->CaretInfo
.hWnd
= hWnd
;
2592 NtUserGetKeyState(INT key
)
2598 Ret
= UserGetKeyState(key
);
2608 NtUserGetKeyboardState(LPBYTE lpKeyState
)
2610 DWORD i
, ret
= TRUE
;
2612 PUSER_MESSAGE_QUEUE MessageQueue
;
2616 pti
= PsGetCurrentThreadWin32Thread();
2617 MessageQueue
= pti
->MessageQueue
;
2621 /* Probe and copy key state to an array */
2622 ProbeForWrite(lpKeyState
, 256 * sizeof(BYTE
), 1);
2623 for (i
= 0; i
< 256; ++i
)
2626 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, i
))
2627 lpKeyState
[i
] |= KS_DOWN_BIT
;
2628 if (IS_KEY_LOCKED(MessageQueue
->afKeyState
, i
))
2629 lpKeyState
[i
] |= KS_LOCK_BIT
;
2632 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2634 SetLastNtError(_SEH2_GetExceptionCode());
2646 NtUserSetKeyboardState(LPBYTE pKeyState
)
2651 PUSER_MESSAGE_QUEUE MessageQueue
;
2653 UserEnterExclusive();
2655 pti
= PsGetCurrentThreadWin32Thread();
2656 MessageQueue
= pti
->MessageQueue
;
2660 ProbeForRead(pKeyState
, 256 * sizeof(BYTE
), 1);
2661 for (i
= 0; i
< 256; ++i
)
2663 SET_KEY_DOWN(MessageQueue
->afKeyState
, i
, pKeyState
[i
] & KS_DOWN_BIT
);
2664 SET_KEY_LOCKED(MessageQueue
->afKeyState
, i
, pKeyState
[i
] & KS_LOCK_BIT
);
2667 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2669 SetLastNtError(_SEH2_GetExceptionCode());