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
;
19 PUSER_MESSAGE_QUEUE gpqCursor
;
20 ULONG_PTR gdwMouseMoveExtraInfo
= 0;
21 DWORD gdwMouseMoveTimeStamp
= 0;
24 /* FUNCTIONS *****************************************************************/
29 MsqInitializeImpl(VOID
)
31 // Setup Post Messages
32 pgMessageLookasideList
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(PAGED_LOOKASIDE_LIST
), TAG_USRMSG
);
33 if (!pgMessageLookasideList
)
34 return STATUS_NO_MEMORY
;
35 ExInitializePagedLookasideList(pgMessageLookasideList
,
42 // Setup Send Messages
43 pgSendMsgLookasideList
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(PAGED_LOOKASIDE_LIST
), TAG_USRMSG
);
44 if (!pgSendMsgLookasideList
)
45 return STATUS_NO_MEMORY
;
46 ExInitializePagedLookasideList(pgSendMsgLookasideList
,
50 sizeof(USER_SENT_MESSAGE
),
54 InitializeListHead(&usmList
);
56 return(STATUS_SUCCESS
);
60 IntTopLevelWindowFromPoint(INT x
, INT y
)
62 PWND pWnd
, pwndDesktop
;
64 /* Get the desktop window */
65 pwndDesktop
= UserGetDesktopWindow();
69 /* Loop all top level windows */
70 for (pWnd
= pwndDesktop
->spwndChild
;
72 pWnd
= pWnd
->spwndNext
)
74 if (pWnd
->state2
& WNDS2_INDESTROY
|| pWnd
->state
& WNDS_DESTROYED
)
76 TRACE("The Window is in DESTROY!\n");
80 if ((pWnd
->style
& WS_VISIBLE
) &&
81 (pWnd
->ExStyle
& (WS_EX_LAYERED
|WS_EX_TRANSPARENT
)) != (WS_EX_LAYERED
|WS_EX_TRANSPARENT
) &&
82 IntPtInWindow(pWnd
, x
, y
))
86 /* Window has not been found */
93 PCURICON_OBJECT NewCursor
,
96 PCURICON_OBJECT OldCursor
;
99 PUSER_MESSAGE_QUEUE MessageQueue
;
102 pti
= PsGetCurrentThreadWin32Thread();
103 MessageQueue
= pti
->MessageQueue
;
105 OldCursor
= MessageQueue
->CursorObject
;
107 /* Check if cursors are different */
108 if (OldCursor
== NewCursor
)
111 /* Update cursor for this message queue */
112 MessageQueue
->CursorObject
= NewCursor
;
114 /* If cursor is not visible we have nothing to do */
115 if (MessageQueue
->iCursorLevel
< 0)
118 // Fixes the error message "Not the same cursor!".
119 if (gpqCursor
== NULL
)
121 gpqCursor
= MessageQueue
;
124 /* Update cursor if this message queue controls it */
125 pWnd
= IntTopLevelWindowFromPoint(gpsi
->ptCursor
.x
, gpsi
->ptCursor
.y
);
126 if (pWnd
&& pWnd
->head
.pti
->MessageQueue
== MessageQueue
)
128 /* Get the screen DC */
129 if (!(hdcScreen
= IntGetScreenDC()))
136 /* Call GDI to set the new screen cursor */
137 PCURICON_OBJECT CursorFrame
= NewCursor
;
138 if(NewCursor
->CURSORF_flags
& CURSORF_ACON
)
140 FIXME("Should animate the cursor, using only the first frame now.\n");
141 CursorFrame
= ((PACON
)NewCursor
)->aspcur
[0];
143 GreSetPointerShape(hdcScreen
,
144 CursorFrame
->hbmAlpha
? NULL
: NewCursor
->hbmMask
,
145 CursorFrame
->hbmAlpha
? NewCursor
->hbmAlpha
: NewCursor
->hbmColor
,
146 CursorFrame
->xHotspot
,
147 CursorFrame
->yHotspot
,
150 CursorFrame
->hbmAlpha
? SPS_ALPHA
: 0);
152 else /* Note: OldCursor != NewCursor so we have to hide cursor */
154 /* Remove the cursor */
155 GreMovePointer(hdcScreen
, -1, -1);
156 TRACE("Removing pointer!\n");
158 IntGetSysCursorInfo()->CurrentCursorObject
= NewCursor
;
161 /* Return the old cursor */
165 /* Called from NtUserCallOneParam with Routine ONEPARAM_ROUTINE_SHOWCURSOR
166 * User32 macro NtUserShowCursor */
167 int UserShowCursor(BOOL bShow
)
171 PUSER_MESSAGE_QUEUE MessageQueue
;
174 if (!(hdcScreen
= IntGetScreenDC()))
176 return -1; /* No mouse */
179 pti
= PsGetCurrentThreadWin32Thread();
180 MessageQueue
= pti
->MessageQueue
;
183 MessageQueue
->iCursorLevel
+= bShow
? 1 : -1;
184 pti
->iCursorLevel
+= bShow
? 1 : -1;
186 /* Check for trivial cases */
187 if ((bShow
&& MessageQueue
->iCursorLevel
!= 0) ||
188 (!bShow
&& MessageQueue
->iCursorLevel
!= -1))
190 /* Note: w don't update global info here because it is used only
191 internally to check if cursor is visible */
192 return MessageQueue
->iCursorLevel
;
195 /* Check if cursor is above window owned by this MessageQueue */
196 pWnd
= IntTopLevelWindowFromPoint(gpsi
->ptCursor
.x
, gpsi
->ptCursor
.y
);
197 if (pWnd
&& pWnd
->head
.pti
->MessageQueue
== MessageQueue
)
201 /* Show the pointer */
202 GreMovePointer(hdcScreen
, gpsi
->ptCursor
.x
, gpsi
->ptCursor
.y
);
203 TRACE("Showing pointer!\n");
207 /* Remove the pointer */
208 GreMovePointer(hdcScreen
, -1, -1);
209 TRACE("Removing pointer!\n");
212 /* Update global info */
213 IntGetSysCursorInfo()->ShowingCursor
= MessageQueue
->iCursorLevel
;
216 return MessageQueue
->iCursorLevel
;
220 UserGetKeyState(DWORD dwKey
)
224 PUSER_MESSAGE_QUEUE MessageQueue
;
226 pti
= PsGetCurrentThreadWin32Thread();
227 MessageQueue
= pti
->MessageQueue
;
231 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, dwKey
))
232 dwRet
|= 0xFF80; // If down, windows returns 0xFF80.
233 if (IS_KEY_LOCKED(MessageQueue
->afKeyState
, dwKey
))
238 EngSetLastError(ERROR_INVALID_PARAMETER
);
243 /* change the input key state for a given key */
245 UpdateKeyState(PUSER_MESSAGE_QUEUE MessageQueue
, WORD wVk
, BOOL bIsDown
)
247 TRACE("UpdateKeyState wVk: %u, bIsDown: %d\n", wVk
, bIsDown
);
251 /* If it's first key down event, xor lock bit */
252 if (!IS_KEY_DOWN(MessageQueue
->afKeyState
, wVk
))
253 SET_KEY_LOCKED(MessageQueue
->afKeyState
, wVk
, !IS_KEY_LOCKED(MessageQueue
->afKeyState
, wVk
));
255 SET_KEY_DOWN(MessageQueue
->afKeyState
, wVk
, TRUE
);
256 MessageQueue
->afKeyRecentDown
[wVk
/ 8] |= (1 << (wVk
% 8));
259 SET_KEY_DOWN(MessageQueue
->afKeyState
, wVk
, FALSE
);
262 /* update the input key state for a keyboard message */
264 UpdateKeyStateFromMsg(PUSER_MESSAGE_QUEUE MessageQueue
, MSG
* msg
)
269 TRACE("UpdateKeyStateFromMsg message:%u\n", msg
->message
);
271 switch (msg
->message
)
277 UpdateKeyState(MessageQueue
, VK_LBUTTON
, down
);
283 UpdateKeyState(MessageQueue
, VK_MBUTTON
, down
);
289 UpdateKeyState(MessageQueue
, VK_RBUTTON
, down
);
295 if (msg
->wParam
== XBUTTON1
)
296 UpdateKeyState(MessageQueue
, VK_XBUTTON1
, down
);
297 else if (msg
->wParam
== XBUTTON2
)
298 UpdateKeyState(MessageQueue
, VK_XBUTTON2
, down
);
306 key
= (UCHAR
)msg
->wParam
;
307 UpdateKeyState(MessageQueue
, key
, down
);
312 down
= IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_LCONTROL
) || IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_RCONTROL
);
313 UpdateKeyState(MessageQueue
, VK_CONTROL
, down
);
317 down
= IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_LMENU
) || IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_RMENU
);
318 UpdateKeyState(MessageQueue
, VK_MENU
, down
);
322 down
= IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_LSHIFT
) || IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_RSHIFT
);
323 UpdateKeyState(MessageQueue
, VK_SHIFT
, down
);
331 Get down key states from the queue of prior processed input message key states.
333 This fixes the left button dragging on the desktop and release sticking outline issue.
334 USB Tablet pointer seems to stick the most and leaves the box outline displayed.
337 MsqGetDownKeyState(PUSER_MESSAGE_QUEUE MessageQueue
)
341 if (gspv
.bMouseBtnSwap
)
343 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_RBUTTON
)) ret
|= MK_LBUTTON
;
344 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_LBUTTON
)) ret
|= MK_RBUTTON
;
348 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_LBUTTON
)) ret
|= MK_LBUTTON
;
349 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_RBUTTON
)) ret
|= MK_RBUTTON
;
352 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_MBUTTON
)) ret
|= MK_MBUTTON
;
353 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_SHIFT
)) ret
|= MK_SHIFT
;
354 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_CONTROL
)) ret
|= MK_CONTROL
;
355 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_XBUTTON1
)) ret
|= MK_XBUTTON1
;
356 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_XBUTTON2
)) ret
|= MK_XBUTTON2
;
361 IntMsqSetWakeMask(DWORD WakeMask
)
363 PTHREADINFO Win32Thread
;
364 HANDLE MessageEventHandle
;
365 DWORD dwFlags
= HIWORD(WakeMask
);
367 Win32Thread
= PsGetCurrentThreadWin32Thread();
368 if (Win32Thread
== NULL
|| Win32Thread
->MessageQueue
== NULL
)
371 // Win32Thread->pEventQueueServer; IntMsqSetWakeMask returns Win32Thread->hEventQueueClient
372 MessageEventHandle
= Win32Thread
->hEventQueueClient
;
374 if (Win32Thread
->pcti
)
376 if ( (Win32Thread
->pcti
->fsChangeBits
& LOWORD(WakeMask
)) ||
377 ( (dwFlags
& MWMO_INPUTAVAILABLE
) && (Win32Thread
->pcti
->fsWakeBits
& LOWORD(WakeMask
)) ) )
379 ERR("Chg 0x%x Wake 0x%x Mask 0x%x\n",Win32Thread
->pcti
->fsChangeBits
, Win32Thread
->pcti
->fsWakeBits
, WakeMask
);
380 KeSetEvent(Win32Thread
->pEventQueueServer
, IO_NO_INCREMENT
, FALSE
); // Wake it up!
381 return MessageEventHandle
;
387 return MessageEventHandle
;
391 IntMsqClearWakeMask(VOID
)
393 PTHREADINFO Win32Thread
;
395 Win32Thread
= PsGetCurrentThreadWin32Thread();
396 if (Win32Thread
== NULL
|| Win32Thread
->MessageQueue
== NULL
)
398 // Very hacky, but that is what they do.
399 Win32Thread
->pcti
->fsWakeBits
= 0;
407 Due to the uncertainty of knowing what was set in our multilevel message queue,
408 and even if the bits are all cleared. The same as cTimers/cPaintsReady.
409 I think this is the best solution... (jt) */
411 MsqWakeQueue(PTHREADINFO pti
, DWORD MessageBits
, BOOL KeyEvent
)
413 PUSER_MESSAGE_QUEUE Queue
;
415 Queue
= pti
->MessageQueue
;
417 if (Queue
->QF_flags
& QF_INDESTROY
)
419 ERR("This Message Queue is in Destroy!\n");
421 pti
->pcti
->fsWakeBits
|= MessageBits
;
422 pti
->pcti
->fsChangeBits
|= MessageBits
;
424 // Start bit accounting to help clear the main set of bits.
425 if (MessageBits
& QS_KEY
)
427 pti
->nCntsQBits
[QSRosKey
]++;
429 if (MessageBits
& QS_MOUSE
)
431 if (MessageBits
& QS_MOUSEMOVE
) pti
->nCntsQBits
[QSRosMouseMove
]++;
432 if (MessageBits
& QS_MOUSEBUTTON
) pti
->nCntsQBits
[QSRosMouseButton
]++;
434 if (MessageBits
& QS_POSTMESSAGE
) pti
->nCntsQBits
[QSRosPostMessage
]++;
435 if (MessageBits
& QS_SENDMESSAGE
) pti
->nCntsQBits
[QSRosSendMessage
]++;
436 if (MessageBits
& QS_HOTKEY
) pti
->nCntsQBits
[QSRosHotKey
]++;
437 if (MessageBits
& QS_EVENT
) pti
->nCntsQBits
[QSRosEvent
]++;
440 KeSetEvent(pti
->pEventQueueServer
, IO_NO_INCREMENT
, FALSE
);
444 ClearMsgBitsMask(PTHREADINFO pti
, UINT MessageBits
)
448 if (MessageBits
& QS_KEY
)
450 if (--pti
->nCntsQBits
[QSRosKey
] == 0) ClrMask
|= QS_KEY
;
452 if (MessageBits
& QS_MOUSEMOVE
)
453 { // Account for tracking mouse moves..
454 if (pti
->nCntsQBits
[QSRosMouseMove
])
456 pti
->nCntsQBits
[QSRosMouseMove
] = 0; // Throttle down count. Up to > 3:1 entries are ignored.
457 ClrMask
|= QS_MOUSEMOVE
;
460 if (MessageBits
& QS_MOUSEBUTTON
)
462 if (--pti
->nCntsQBits
[QSRosMouseButton
] == 0) ClrMask
|= QS_MOUSEBUTTON
;
464 if (MessageBits
& QS_POSTMESSAGE
)
466 if (--pti
->nCntsQBits
[QSRosPostMessage
] == 0) ClrMask
|= QS_POSTMESSAGE
;
468 if (MessageBits
& QS_TIMER
) // ReactOS hard coded.
469 { // Handle timer bits here.
470 if ( pti
->cTimersReady
)
472 if (--pti
->cTimersReady
== 0) ClrMask
|= QS_TIMER
;
475 if (MessageBits
& QS_PAINT
) // ReactOS hard coded.
476 { // Handle paint bits here.
477 if ( pti
->cPaintsReady
)
479 if (--pti
->cPaintsReady
== 0) ClrMask
|= QS_PAINT
;
482 if (MessageBits
& QS_SENDMESSAGE
)
484 if (--pti
->nCntsQBits
[QSRosSendMessage
] == 0) ClrMask
|= QS_SENDMESSAGE
;
486 if (MessageBits
& QS_HOTKEY
)
488 if (--pti
->nCntsQBits
[QSRosHotKey
] == 0) ClrMask
|= QS_HOTKEY
;
490 if (MessageBits
& QS_EVENT
)
492 if (--pti
->nCntsQBits
[QSRosEvent
] == 0) ClrMask
|= QS_EVENT
;
495 pti
->pcti
->fsWakeBits
&= ~ClrMask
;
496 pti
->pcti
->fsChangeBits
&= ~ClrMask
;
500 MsqIncPaintCountQueue(PTHREADINFO pti
)
503 MsqWakeQueue(pti
, QS_PAINT
, TRUE
);
507 MsqDecPaintCountQueue(PTHREADINFO pti
)
509 ClearMsgBitsMask(pti
, QS_PAINT
);
513 Post the move or update the message still pending to be processed.
514 Do not overload the queue with mouse move messages.
517 MsqPostMouseMove(PTHREADINFO pti
, MSG
* Msg
, LONG_PTR ExtraInfo
)
519 PUSER_MESSAGE Message
;
520 PLIST_ENTRY ListHead
;
521 PUSER_MESSAGE_QUEUE MessageQueue
= pti
->MessageQueue
;
523 ListHead
= &MessageQueue
->HardwareMessagesListHead
;
525 // Do nothing if empty.
526 if (!IsListEmpty(ListHead
->Flink
))
528 // Look at the end of the list,
529 Message
= CONTAINING_RECORD(ListHead
->Blink
, USER_MESSAGE
, ListEntry
);
531 // If the mouse move message is existing on the list,
532 if (Message
->Msg
.message
== WM_MOUSEMOVE
)
534 // Overwrite the message with updated data!
537 MsqWakeQueue(pti
, QS_MOUSEMOVE
, TRUE
);
542 MsqPostMessage(pti
, Msg
, TRUE
, QS_MOUSEMOVE
, 0, ExtraInfo
);
546 Bring together the mouse move message.
547 Named "Coalesce" from Amine email ;^) (jt).
550 IntCoalesceMouseMove(PTHREADINFO pti
)
553 LARGE_INTEGER LargeTickCount
;
555 // Force time stamp to update, keeping message time in sync.
556 if (gdwMouseMoveTimeStamp
== 0)
558 KeQueryTickCount(&LargeTickCount
);
559 gdwMouseMoveTimeStamp
= MsqCalculateMessageTime(&LargeTickCount
);
562 // Build mouse move message.
564 Msg
.message
= WM_MOUSEMOVE
;
566 Msg
.lParam
= MAKELONG(gpsi
->ptCursor
.x
, gpsi
->ptCursor
.y
);
567 Msg
.time
= gdwMouseMoveTimeStamp
;
568 Msg
.pt
= gpsi
->ptCursor
;
571 MsqPostMouseMove(pti
, &Msg
, gdwMouseMoveExtraInfo
);
573 // Zero the time stamp.
574 gdwMouseMoveTimeStamp
= 0;
576 // Clear flag since the move was posted.
577 pti
->MessageQueue
->QF_flags
&= ~QF_MOUSEMOVED
;
581 co_MsqInsertMouseMessage(MSG
* Msg
, DWORD flags
, ULONG_PTR dwExtraInfo
, BOOL Hook
)
583 LARGE_INTEGER LargeTickCount
;
584 MSLLHOOKSTRUCT MouseHookData
;
586 PWND pwnd
, pwndDesktop
;
589 PUSER_MESSAGE_QUEUE MessageQueue
;
590 PSYSTEM_CURSORINFO CurInfo
;
592 KeQueryTickCount(&LargeTickCount
);
593 Msg
->time
= MsqCalculateMessageTime(&LargeTickCount
);
595 MouseHookData
.pt
.x
= LOWORD(Msg
->lParam
);
596 MouseHookData
.pt
.y
= HIWORD(Msg
->lParam
);
597 switch (Msg
->message
)
600 MouseHookData
.mouseData
= MAKELONG(0, GET_WHEEL_DELTA_WPARAM(Msg
->wParam
));
604 case WM_XBUTTONDBLCLK
:
605 case WM_NCXBUTTONDOWN
:
607 case WM_NCXBUTTONDBLCLK
:
608 MouseHookData
.mouseData
= MAKELONG(0, HIWORD(Msg
->wParam
));
611 MouseHookData
.mouseData
= 0;
615 MouseHookData
.flags
= flags
; // LLMHF_INJECTED
616 MouseHookData
.time
= Msg
->time
;
617 MouseHookData
.dwExtraInfo
= dwExtraInfo
;
619 /* If the hook procedure returned non zero, dont send the message */
622 if (co_HOOK_CallHooks(WH_MOUSE_LL
, HC_ACTION
, Msg
->message
, (LPARAM
) &MouseHookData
))
626 /* Get the desktop window */
627 pwndDesktop
= UserGetDesktopWindow();
628 if (!pwndDesktop
) return;
629 // pDesk = pwndDesktop->head.rpdesk;
631 /* Check if the mouse is captured */
632 Msg
->hwnd
= IntGetCaptureWindow();
633 if (Msg
->hwnd
!= NULL
)
635 pwnd
= UserGetWindowObject(Msg
->hwnd
);
639 pwnd
= IntTopLevelWindowFromPoint(Msg
->pt
.x
, Msg
->pt
.y
);
640 if (pwnd
) Msg
->hwnd
= pwnd
->head
.h
;
643 hdcScreen
= IntGetScreenDC();
644 CurInfo
= IntGetSysCursorInfo();
646 /* Check if we found a window */
647 if (Msg
->hwnd
!= NULL
&& pwnd
!= NULL
)
649 pti
= pwnd
->head
.pti
;
650 MessageQueue
= pti
->MessageQueue
;
652 if (MessageQueue
->QF_flags
& QF_INDESTROY
)
654 ERR("Mouse is over a Window with a Dead Message Queue!\n");
658 // Check to see if this is attached.
659 if ( pti
!= MessageQueue
->ptiMouse
&&
660 MessageQueue
->cThreads
> 1 )
662 // Set the send pti to the message queue mouse pti.
663 pti
= MessageQueue
->ptiMouse
;
666 if (Msg
->message
== WM_MOUSEMOVE
)
668 /* Check if cursor should be visible */
670 MessageQueue
->CursorObject
&&
671 MessageQueue
->iCursorLevel
>= 0)
673 /* Check if shape has changed */
674 if(CurInfo
->CurrentCursorObject
!= MessageQueue
->CursorObject
)
676 /* Call GDI to set the new screen cursor */
677 GreSetPointerShape(hdcScreen
,
678 MessageQueue
->CursorObject
->hbmAlpha
?
679 NULL
: MessageQueue
->CursorObject
->hbmMask
,
680 MessageQueue
->CursorObject
->hbmAlpha
?
681 MessageQueue
->CursorObject
->hbmAlpha
: MessageQueue
->CursorObject
->hbmColor
,
682 MessageQueue
->CursorObject
->xHotspot
,
683 MessageQueue
->CursorObject
->yHotspot
,
686 MessageQueue
->CursorObject
->hbmAlpha
? SPS_ALPHA
: 0);
689 GreMovePointer(hdcScreen
, Msg
->pt
.x
, Msg
->pt
.y
);
691 /* Check if we have to hide cursor */
692 else if (CurInfo
->ShowingCursor
>= 0)
693 GreMovePointer(hdcScreen
, -1, -1);
695 /* Update global cursor info */
696 CurInfo
->ShowingCursor
= MessageQueue
->iCursorLevel
;
697 CurInfo
->CurrentCursorObject
= MessageQueue
->CursorObject
;
698 gpqCursor
= MessageQueue
;
700 /* Mouse move is a special case */
701 MessageQueue
->QF_flags
|= QF_MOUSEMOVED
;
702 gdwMouseMoveExtraInfo
= dwExtraInfo
;
703 gdwMouseMoveTimeStamp
= Msg
->time
;
704 MsqWakeQueue(pti
, QS_MOUSEMOVE
, TRUE
);
708 if (!IntGetCaptureWindow())
710 // ERR("ptiLastInput is set\n");
711 // ptiLastInput = pti; // Once this is set during Reboot or Shutdown, this prevents the exit window having foreground.
712 // Find all the Move Mouse calls and fix mouse set active focus issues......
715 // Post mouse move before posting mouse buttons, keep it in sync.
716 if (pti
->MessageQueue
->QF_flags
& QF_MOUSEMOVED
)
718 IntCoalesceMouseMove(pti
);
721 TRACE("Posting mouse message to hwnd=%p!\n", UserHMGetHandle(pwnd
));
722 MsqPostMessage(pti
, Msg
, TRUE
, QS_MOUSEBUTTON
, 0, dwExtraInfo
);
727 /* always show cursor on background; FIXME: set default pointer */
728 GreMovePointer(hdcScreen
, Msg
->pt
.x
, Msg
->pt
.y
);
729 CurInfo
->ShowingCursor
= 0;
733 PUSER_MESSAGE FASTCALL
734 MsqCreateMessage(LPMSG Msg
)
736 PUSER_MESSAGE Message
;
738 Message
= ExAllocateFromPagedLookasideList(pgMessageLookasideList
);
744 RtlZeroMemory(Message
, sizeof(*Message
));
745 RtlMoveMemory(&Message
->Msg
, Msg
, sizeof(MSG
));
751 MsqDestroyMessage(PUSER_MESSAGE Message
)
753 if (Message
->pti
== NULL
)
755 ERR("Double Free Message\n");
759 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 RemoveEntryList(&PostedMessage
->ListEntry
);
824 ClearMsgBitsMask(pti
, PostedMessage
->QS_Flags
);
825 MsqDestroyMessage(PostedMessage
);
826 CurrentEntry
= pti
->PostedMessagesListHead
.Flink
;
830 CurrentEntry
= CurrentEntry
->Flink
;
834 /* remove the sent messages for this window */
835 CurrentEntry
= pti
->SentMessagesListHead
.Flink
;
836 ListHead
= &pti
->SentMessagesListHead
;
837 while (CurrentEntry
!= ListHead
)
839 SentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
, ListEntry
);
841 if(SentMessage
->Msg
.hwnd
== Window
->head
.h
)
843 ERR("Remove Window Messages %p From Sent Queue\n",SentMessage
);
844 #if 0 // Should mark these as invalid and allow the rest clean up, so far no harm by just commenting out. See CORE-9210.
845 ClearMsgBitsMask(pti
, SentMessage
->QS_Flags
);
847 /* wake the sender's thread */
848 if (SentMessage
->pkCompletionEvent
!= NULL
)
850 KeSetEvent(SentMessage
->pkCompletionEvent
, IO_NO_INCREMENT
, FALSE
);
853 if (SentMessage
->HasPackedLParam
)
855 if (SentMessage
->Msg
.lParam
)
856 ExFreePool((PVOID
)SentMessage
->Msg
.lParam
);
859 /* free the message */
860 FreeUserMessage(SentMessage
);
862 CurrentEntry
= pti
->SentMessagesListHead
.Flink
;
864 CurrentEntry
= CurrentEntry
->Flink
;
868 CurrentEntry
= CurrentEntry
->Flink
;
874 co_MsqDispatchOneSentMessage(
875 _In_ PTHREADINFO pti
)
877 PUSER_SENT_MESSAGE SaveMsg
, Message
;
882 ASSERT(pti
== PsGetCurrentThreadWin32Thread());
884 if (IsListEmpty(&pti
->SentMessagesListHead
))
889 /* remove it from the list of pending messages */
890 Entry
= RemoveHeadList(&pti
->SentMessagesListHead
);
891 Message
= CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
);
893 // Signal this message is being processed.
894 Message
->flags
|= SMF_RECEIVERBUSY
|SMF_RECEIVEDMESSAGE
;
896 SaveMsg
= pti
->pusmCurrent
;
897 pti
->pusmCurrent
= Message
;
899 // Processing a message sent to it from another thread.
900 if ( ( Message
->ptiSender
&& pti
!= Message
->ptiSender
) ||
901 ( Message
->ptiCallBackSender
&& pti
!= Message
->ptiCallBackSender
))
902 { // most likely, but, to be sure.
903 pti
->pcti
->CTI_flags
|= CTI_INSENDMESSAGE
; // Let the user know...
906 /* Now insert it to the global list of messages that can be removed Justin Case there's Trouble */
907 InsertTailList(&usmList
, &Message
->ListEntry
);
909 ClearMsgBitsMask(pti
, Message
->QS_Flags
);
911 if (Message
->HookMessage
== MSQ_ISHOOK
)
912 { // Direct Hook Call processor
913 Result
= co_CallHook( Message
->Msg
.message
, // HookId
914 (INT
)(INT_PTR
)Message
->Msg
.hwnd
, // Code
916 Message
->Msg
.lParam
);
918 else if(Message
->HookMessage
== MSQ_INJECTMODULE
)
920 Result
= IntLoadHookModule(Message
->Msg
.message
,
921 (HHOOK
)Message
->Msg
.lParam
,
922 Message
->Msg
.wParam
);
924 else if ((Message
->CompletionCallback
) &&
925 (Message
->ptiCallBackSender
== pti
))
926 { /* Call the callback routine */
927 if (Message
->QS_Flags
& QS_SMRESULT
)
929 co_IntCallSentMessageCallback(Message
->CompletionCallback
,
931 Message
->Msg
.message
,
932 Message
->CompletionCallbackContext
,
934 /* Set callback to NULL to prevent reentry */
935 Message
->CompletionCallback
= NULL
;
939 /* The message has not been processed yet, reinsert it. */
940 RemoveEntryList(&Message
->ListEntry
);
941 InsertTailList(&Message
->ptiCallBackSender
->SentMessagesListHead
, &Message
->ListEntry
);
942 // List is occupied need to set the bit.
943 MsqWakeQueue(Message
->ptiCallBackSender
, QS_SENDMESSAGE
, TRUE
);
944 ERR("Callback Message not processed yet. Requeuing the message\n"); //// <---- Need to see if this happens.
950 { /* Call the window procedure. */
951 Result
= co_IntSendMessage( Message
->Msg
.hwnd
,
952 Message
->Msg
.message
,
954 Message
->Msg
.lParam
);
957 /* If the message is a callback, insert it in the callback senders MessageQueue */
958 if (Message
->CompletionCallback
)
960 if (Message
->ptiCallBackSender
)
962 Message
->lResult
= Result
;
963 Message
->QS_Flags
|= QS_SMRESULT
;
965 /* insert it in the callers message queue */
966 RemoveEntryList(&Message
->ListEntry
);
967 InsertTailList(&Message
->ptiCallBackSender
->SentMessagesListHead
, &Message
->ListEntry
);
968 MsqWakeQueue(Message
->ptiCallBackSender
, QS_SENDMESSAGE
, TRUE
);
974 // Retrieve the result from callback.
975 if (Message
->QS_Flags
& QS_SMRESULT
)
977 Result
= Message
->lResult
;
980 /* Let the sender know the result. */
981 Message
->lResult
= Result
;
983 if (Message
->HasPackedLParam
)
985 if (Message
->Msg
.lParam
)
986 ExFreePool((PVOID
)Message
->Msg
.lParam
);
989 // Clear busy signal.
990 Message
->flags
&= ~SMF_RECEIVERBUSY
;
992 /* Notify the sender. */
993 if (Message
->pkCompletionEvent
!= NULL
)
995 KeSetEvent(Message
->pkCompletionEvent
, IO_NO_INCREMENT
, FALSE
);
998 /* free the message */
999 if (Message
->flags
& SMF_RECEIVERFREE
)
1001 TRACE("Receiver Freeing Message %p\n",Message
);
1002 FreeUserMessage(Message
);
1007 /* do not hangup on the user if this is reentering */
1008 if (!SaveMsg
) pti
->pcti
->CTI_flags
&= ~CTI_INSENDMESSAGE
;
1009 pti
->pusmCurrent
= SaveMsg
;
1015 co_MsqSendMessageAsync(PTHREADINFO ptiReceiver
,
1020 SENDASYNCPROC CompletionCallback
,
1021 ULONG_PTR CompletionCallbackContext
,
1022 BOOL HasPackedLParam
,
1026 PTHREADINFO ptiSender
;
1027 PUSER_SENT_MESSAGE Message
;
1029 if(!(Message
= AllocateUserMessage(FALSE
)))
1031 ERR("MsqSendMessageAsync(): Not enough memory to allocate a message");
1035 ptiSender
= PsGetCurrentThreadWin32Thread();
1037 Message
->Msg
.hwnd
= hwnd
;
1038 Message
->Msg
.message
= Msg
;
1039 Message
->Msg
.wParam
= wParam
;
1040 Message
->Msg
.lParam
= lParam
;
1041 Message
->pkCompletionEvent
= NULL
; // No event needed.
1042 Message
->ptiReceiver
= ptiReceiver
;
1043 Message
->ptiCallBackSender
= ptiSender
;
1044 Message
->CompletionCallback
= CompletionCallback
;
1045 Message
->CompletionCallbackContext
= CompletionCallbackContext
;
1046 Message
->HookMessage
= HookMessage
;
1047 Message
->HasPackedLParam
= HasPackedLParam
;
1048 Message
->QS_Flags
= QS_SENDMESSAGE
;
1049 Message
->flags
= SMF_RECEIVERFREE
;
1051 InsertTailList(&ptiReceiver
->SentMessagesListHead
, &Message
->ListEntry
);
1052 MsqWakeQueue(ptiReceiver
, QS_SENDMESSAGE
, TRUE
);
1058 co_MsqSendMessage(PTHREADINFO ptirec
,
1069 PUSER_SENT_MESSAGE SaveMsg
, Message
;
1070 NTSTATUS WaitStatus
;
1071 LARGE_INTEGER Timeout
;
1074 BOOLEAN SwapStateEnabled
;
1075 LRESULT Result
= 0; //// Result could be trashed. ////
1077 pti
= PsGetCurrentThreadWin32Thread();
1078 ASSERT(pti
!= ptirec
);
1079 ASSERT(ptirec
->pcti
); // Send must have a client side to receive it!!!!
1081 /* Don't send from or to a dying thread */
1082 if (pti
->TIF_flags
& TIF_INCLEANUP
|| ptirec
->TIF_flags
& TIF_INCLEANUP
)
1084 // Unless we are dying and need to tell our parents.
1085 if (pti
->TIF_flags
& TIF_INCLEANUP
&& !(ptirec
->TIF_flags
& TIF_INCLEANUP
))
1087 // Parent notify is the big one. Fire and forget!
1088 TRACE("Send message from dying thread %u\n", Msg
);
1089 co_MsqSendMessageAsync(ptirec
, Wnd
, Msg
, wParam
, lParam
, NULL
, 0, FALSE
, HookMessage
);
1091 if (uResult
) *uResult
= -1;
1092 TRACE("MsqSM: Msg %u Current pti %lu or Rec pti %lu\n", Msg
, pti
->TIF_flags
& TIF_INCLEANUP
, ptirec
->TIF_flags
& TIF_INCLEANUP
);
1093 return STATUS_UNSUCCESSFUL
;
1096 if (IsThreadSuspended(ptirec
))
1098 ERR("Sending to Suspended Thread Msg %lx\n",Msg
);
1099 if (uResult
) *uResult
= -1;
1100 return STATUS_UNSUCCESSFUL
;
1103 // Should we do the same for No Wait?
1104 if ( HookMessage
== MSQ_NORMAL
)
1106 pWnd
= ValidateHwndNoErr(Wnd
);
1108 // These can not cross International Border lines!
1109 if ( pti
->ppi
!= ptirec
->ppi
&& pWnd
)
1113 // Handle the special case when working with password transfers across bordering processes.
1115 case EM_SETPASSWORDCHAR
:
1117 // Look for edit controls setup for passwords.
1118 if ( gpsi
->atomSysClass
[ICLS_EDIT
] == pWnd
->pcls
->atomClassName
&& // Use atomNVClassName.
1119 pWnd
->style
& ES_PASSWORD
)
1121 if (uResult
) *uResult
= -1;
1122 ERR("Running across the border without a passport!\n");
1123 EngSetLastError(ERROR_ACCESS_DENIED
);
1124 return STATUS_UNSUCCESSFUL
;
1128 if (uResult
) *uResult
= -1;
1129 ERR("Running across the border without a passport!\n");
1130 return STATUS_UNSUCCESSFUL
;
1134 // These can not cross State lines!
1135 if ( Msg
== WM_CREATE
|| Msg
== WM_NCCREATE
)
1137 if (uResult
) *uResult
= -1;
1138 ERR("Can not tell the other State we have Create!\n");
1139 return STATUS_UNSUCCESSFUL
;
1143 if(!(Message
= AllocateUserMessage(TRUE
)))
1145 ERR("MsqSendMessage(): Not enough memory to allocate a message\n");
1146 if (uResult
) *uResult
= -1;
1147 return STATUS_INSUFFICIENT_RESOURCES
;
1150 Timeout
.QuadPart
= Int32x32To64(-10000,uTimeout
); // Pass SMTO test with a TO of 0x80000000.
1151 TRACE("Timeout val %lld\n",Timeout
.QuadPart
)
1153 Message
->Msg
.hwnd
= Wnd
;
1154 Message
->Msg
.message
= Msg
;
1155 Message
->Msg
.wParam
= wParam
;
1156 Message
->Msg
.lParam
= lParam
;
1157 Message
->ptiReceiver
= ptirec
;
1158 Message
->ptiSender
= pti
;
1159 Message
->HookMessage
= HookMessage
;
1160 Message
->QS_Flags
= QS_SENDMESSAGE
;
1162 SaveMsg
= pti
->pusmSent
;
1163 pti
->pusmSent
= Message
;
1165 /* Queue it in the destination's message queue */
1166 InsertTailList(&ptirec
->SentMessagesListHead
, &Message
->ListEntry
);
1168 MsqWakeQueue(ptirec
, QS_SENDMESSAGE
, TRUE
);
1170 // First time in, turn off swapping of the stack.
1171 if (pti
->cEnterCount
== 0)
1173 SwapStateEnabled
= KeSetKernelStackSwapEnable(FALSE
);
1179 PVOID WaitObjects
[2];
1181 WaitObjects
[0] = Message
->pkCompletionEvent
; // Wait 0
1182 WaitObjects
[1] = ptirec
->pEThread
; // Wait 1
1186 WaitStatus
= KeWaitForMultipleObjects( 2,
1192 (uTimeout
? &Timeout
: NULL
),
1197 if (WaitStatus
== STATUS_TIMEOUT
)
1199 /* Look up if the message has not yet dispatched, if so
1200 make sure it can't pass a result and it must not set the completion event anymore */
1201 Entry
= ptirec
->SentMessagesListHead
.Flink
;
1202 while (Entry
!= &ptirec
->SentMessagesListHead
)
1204 if (CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
) == Message
)
1206 Message
->pkCompletionEvent
= NULL
;
1207 RemoveEntryList(&Message
->ListEntry
);
1208 ClearMsgBitsMask(ptirec
, Message
->QS_Flags
);
1209 InsertTailList(&usmList
, &Message
->ListEntry
);
1212 Entry
= Entry
->Flink
;
1215 ERR("MsqSendMessage (blocked) timed out 1 Status %lx\n", WaitStatus
);
1217 // Receiving thread passed on and left us hanging with issues still pending.
1218 else if (WaitStatus
== STATUS_WAIT_1
)
1220 ERR("Bk Receiving Thread woken up dead!\n");
1221 Message
->flags
|= SMF_RECEIVERDIED
;
1224 while (co_MsqDispatchOneSentMessage(pti
))
1229 PVOID WaitObjects
[3];
1231 WaitObjects
[0] = Message
->pkCompletionEvent
; // Wait 0
1232 WaitObjects
[1] = pti
->pEventQueueServer
; // Wait 1
1233 WaitObjects
[2] = ptirec
->pEThread
; // Wait 2
1239 WaitStatus
= KeWaitForMultipleObjects( 3,
1245 (uTimeout
? &Timeout
: NULL
),
1250 if (WaitStatus
== STATUS_TIMEOUT
)
1252 /* Look up if the message has not yet been dispatched, if so
1253 make sure it can't pass a result and it must not set the completion event anymore */
1254 Entry
= ptirec
->SentMessagesListHead
.Flink
;
1255 while (Entry
!= &ptirec
->SentMessagesListHead
)
1257 if (CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
) == Message
)
1259 Message
->pkCompletionEvent
= NULL
;
1260 RemoveEntryList(&Message
->ListEntry
);
1261 ClearMsgBitsMask(ptirec
, Message
->QS_Flags
);
1262 InsertTailList(&usmList
, &Message
->ListEntry
);
1265 Entry
= Entry
->Flink
;
1268 ERR("MsqSendMessage timed out 2 Status %lx\n", WaitStatus
);
1271 // Receiving thread passed on and left us hanging with issues still pending.
1272 else if (WaitStatus
== STATUS_WAIT_2
)
1274 ERR("NB Receiving Thread woken up dead!\n");
1275 Message
->flags
|= SMF_RECEIVERDIED
;
1279 if (WaitStatus
== STATUS_USER_APC
) break;
1281 while (co_MsqDispatchOneSentMessage(pti
))
1283 } while (WaitStatus
== STATUS_WAIT_1
);
1286 // Count is nil, restore swapping of the stack.
1287 if (--pti
->cEnterCount
== 0 )
1289 KeSetKernelStackSwapEnable(SwapStateEnabled
);
1293 if (WaitStatus
== STATUS_USER_APC
)
1295 // The current thread is dying!
1296 TRACE("User APC\n");
1298 // The Message will be on the Trouble list until Thread cleanup.
1299 Message
->flags
|= SMF_SENDERDIED
;
1301 co_IntDeliverUserAPC();
1302 ERR("User APC Returned\n"); // Should not see this message.
1305 // Force this thread to wake up for the next go around.
1306 KeSetEvent(pti
->pEventQueueServer
, IO_NO_INCREMENT
, FALSE
);
1308 Result
= Message
->lResult
;
1310 // Determine whether this message is being processed or not.
1311 if ((Message
->flags
& (SMF_RECEIVERBUSY
|SMF_RECEIVEDMESSAGE
)) != SMF_RECEIVEDMESSAGE
)
1313 Message
->flags
|= SMF_RECEIVERFREE
;
1316 if (!(Message
->flags
& SMF_RECEIVERFREE
))
1318 TRACE("Sender Freeing Message %p ptirec %p bit %d list empty %d\n",Message
,ptirec
,!!(ptirec
->pcti
->fsChangeBits
& QS_SENDMESSAGE
),IsListEmpty(&ptirec
->SentMessagesListHead
));
1319 // Make it to this point, the message was received.
1320 FreeUserMessage(Message
);
1323 pti
->pusmSent
= SaveMsg
;
1325 TRACE("MSM Allocation Count %d Status %lx Result %d\n",SendMsgCount
,WaitStatus
,Result
);
1327 if (WaitStatus
!= STATUS_TIMEOUT
)
1331 *uResult
= (STATUS_WAIT_0
== WaitStatus
? Result
: 0);
1339 MsqPostMessage(PTHREADINFO pti
,
1341 BOOLEAN HardwareMessage
,
1346 PUSER_MESSAGE Message
;
1347 PUSER_MESSAGE_QUEUE MessageQueue
;
1349 if ( pti
->TIF_flags
& TIF_INCLEANUP
|| pti
->MessageQueue
->QF_flags
& QF_INDESTROY
)
1351 ERR("Post Msg; Thread or Q is Dead!\n");
1355 if(!(Message
= MsqCreateMessage(Msg
)))
1360 MessageQueue
= pti
->MessageQueue
;
1362 if (!HardwareMessage
)
1364 InsertTailList(&pti
->PostedMessagesListHead
, &Message
->ListEntry
);
1368 InsertTailList(&MessageQueue
->HardwareMessagesListHead
, &Message
->ListEntry
);
1371 if (Msg
->message
== WM_HOTKEY
) MessageBits
|= QS_HOTKEY
; // Justin Case, just set it.
1372 Message
->dwQEvent
= dwQEvent
;
1373 Message
->ExtraInfo
= ExtraInfo
;
1374 Message
->QS_Flags
= MessageBits
;
1376 MsqWakeQueue(pti
, MessageBits
, TRUE
);
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
, 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 UserSetCursor(SYSTEMCUR(ARROW
), FALSE
);
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 /* message is accepted now (but still get dropped) */
1658 event
.message
= msg
->message
;
1659 event
.time
= msg
->time
;
1660 event
.hwnd
= msg
->hwnd
;
1661 event
.paramL
= msg
->pt
.x
;
1662 event
.paramH
= msg
->pt
.y
;
1663 co_HOOK_CallHooks( WH_JOURNALRECORD
, HC_ACTION
, 0, (LPARAM
)&event
);
1666 hook
.hwnd
= msg
->hwnd
;
1667 hook
.wHitTestCode
= hittest
;
1668 hook
.dwExtraInfo
= 0 /* extra_info */ ;
1669 if (co_HOOK_CallHooks( WH_MOUSE
, *RemoveMessages
? HC_ACTION
: HC_NOREMOVE
,
1670 message
, (LPARAM
)&hook
))
1673 hook
.hwnd
= msg
->hwnd
;
1674 hook
.wHitTestCode
= hittest
;
1675 hook
.dwExtraInfo
= 0 /* extra_info */ ;
1676 co_HOOK_CallHooks( WH_CBT
, HCBT_CLICKSKIPPED
, message
, (LPARAM
)&hook
);
1678 ERR("WH_MOUSE dropped mouse message!\n");
1680 /* Remove and skip message */
1681 *RemoveMessages
= TRUE
;
1685 if ((hittest
== (USHORT
)HTERROR
) || (hittest
== (USHORT
)HTNOWHERE
))
1687 co_IntSendMessage( msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)msg
->hwnd
, MAKELONG( hittest
, msg
->message
));
1689 /* Remove and skip message */
1690 *RemoveMessages
= TRUE
;
1694 if ((*RemoveMessages
== FALSE
) || MessageQueue
->spwndCapture
)
1696 /* Accept the message */
1697 msg
->message
= message
;
1701 if ((msg
->message
== WM_LBUTTONDOWN
) ||
1702 (msg
->message
== WM_RBUTTONDOWN
) ||
1703 (msg
->message
== WM_MBUTTONDOWN
) ||
1704 (msg
->message
== WM_XBUTTONDOWN
))
1706 /* Send the WM_PARENTNOTIFY,
1707 * note that even for double/nonclient clicks
1708 * notification message is still WM_L/M/RBUTTONDOWN.
1710 MsqSendParentNotify(pwndMsg
, msg
->message
, 0, msg
->pt
);
1712 /* Activate the window if needed */
1714 if (pwndMsg
!= MessageQueue
->spwndActive
)
1716 PWND pwndTop
= pwndMsg
;
1717 pwndTop
= IntGetNonChildAncestor(pwndTop
);
1719 TRACE("Mouse pti %p pwndMsg pti %p pwndTop pti %p\n",MessageQueue
->ptiMouse
,pwndMsg
->head
.pti
,pwndTop
->head
.pti
);
1721 if (pwndTop
&& pwndTop
!= pwndDesktop
)
1723 LONG ret
= co_IntSendMessage( msg
->hwnd
,
1725 (WPARAM
)UserHMGetHandle(pwndTop
),
1726 MAKELONG( hittest
, msg
->message
));
1729 case MA_NOACTIVATEANDEAT
:
1734 case MA_ACTIVATEANDEAT
:
1739 if (!co_IntMouseActivateWindow( pwndTop
)) eatMsg
= TRUE
;
1742 ERR( "unknown WM_MOUSEACTIVATE code %d\n", ret
);
1749 /* send the WM_SETCURSOR message */
1751 /* Windows sends the normal mouse message as the message parameter
1752 in the WM_SETCURSOR message even if it's non-client mouse message */
1753 co_IntSendMessage( msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)msg
->hwnd
, MAKELONG( hittest
, msg
->message
));
1755 msg
->message
= message
;
1759 BOOL
co_IntProcessKeyboardMessage(MSG
* Msg
, BOOL
* RemoveMessages
)
1762 USER_REFERENCE_ENTRY Ref
;
1766 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
1768 if (Msg
->message
== VK_PACKET
)
1770 pti
->wchInjected
= HIWORD(Msg
->wParam
);
1773 if (Msg
->message
== WM_KEYDOWN
|| Msg
->message
== WM_SYSKEYDOWN
||
1774 Msg
->message
== WM_KEYUP
|| Msg
->message
== WM_SYSKEYUP
)
1776 switch (Msg
->wParam
)
1778 case VK_LSHIFT
: case VK_RSHIFT
:
1779 Msg
->wParam
= VK_SHIFT
;
1781 case VK_LCONTROL
: case VK_RCONTROL
:
1782 Msg
->wParam
= VK_CONTROL
;
1784 case VK_LMENU
: case VK_RMENU
:
1785 Msg
->wParam
= VK_MENU
;
1790 pWnd
= ValidateHwndNoErr(Msg
->hwnd
);
1791 if (pWnd
) UserRefObjectCo(pWnd
, &Ref
);
1793 Event
.message
= Msg
->message
;
1794 Event
.hwnd
= Msg
->hwnd
;
1795 Event
.time
= Msg
->time
;
1796 Event
.paramL
= (Msg
->wParam
& 0xFF) | (HIWORD(Msg
->lParam
) << 8);
1797 Event
.paramH
= Msg
->lParam
& 0x7FFF;
1798 if (HIWORD(Msg
->lParam
) & 0x0100) Event
.paramH
|= 0x8000;
1799 co_HOOK_CallHooks( WH_JOURNALRECORD
, HC_ACTION
, 0, (LPARAM
)&Event
);
1801 if (*RemoveMessages
)
1803 if ((Msg
->message
== WM_KEYDOWN
) &&
1804 (Msg
->hwnd
!= IntGetDesktopWindow()))
1806 /* Handle F1 key by sending out WM_HELP message */
1807 if (Msg
->wParam
== VK_F1
)
1809 UserPostMessage( Msg
->hwnd
, WM_KEYF1
, 0, 0 );
1811 else if (Msg
->wParam
>= VK_BROWSER_BACK
&&
1812 Msg
->wParam
<= VK_LAUNCH_APP2
)
1814 /* FIXME: Process keystate */
1815 co_IntSendMessage(Msg
->hwnd
, WM_APPCOMMAND
, (WPARAM
)Msg
->hwnd
, MAKELPARAM(0, (FAPPCOMMAND_KEY
| (Msg
->wParam
- VK_BROWSER_BACK
+ 1))));
1818 else if (Msg
->message
== WM_KEYUP
)
1820 /* Handle VK_APPS key by posting a WM_CONTEXTMENU message */
1821 if (Msg
->wParam
== VK_APPS
&& pti
->MessageQueue
->MenuOwner
== NULL
)
1822 UserPostMessage( Msg
->hwnd
, WM_CONTEXTMENU
, (WPARAM
)Msg
->hwnd
, -1 );
1826 if (co_HOOK_CallHooks( WH_KEYBOARD
,
1827 *RemoveMessages
? HC_ACTION
: HC_NOREMOVE
,
1828 LOWORD(Msg
->wParam
),
1831 /* skip this message */
1832 co_HOOK_CallHooks( WH_CBT
,
1834 LOWORD(Msg
->wParam
),
1837 ERR("KeyboardMessage WH_KEYBOARD Call Hook return!\n");
1839 *RemoveMessages
= TRUE
;
1844 if ( pWnd
&& Ret
&& *RemoveMessages
&& Msg
->message
== WM_KEYDOWN
&& !(pti
->TIF_flags
& TIF_DISABLEIME
))
1846 if ( (ImmRet
= IntImmProcessKey(pti
->MessageQueue
, pWnd
, Msg
->message
, Msg
->wParam
, Msg
->lParam
)) )
1848 if ( ImmRet
& (IPHK_HOTKEY
|IPHK_SKIPTHISKEY
) )
1852 if ( ImmRet
& IPHK_PROCESSBYIME
)
1854 Msg
->wParam
= VK_PROCESSKEY
;
1859 if (pWnd
) UserDerefObjectCo(pWnd
);
1863 BOOL
co_IntProcessHardwareMessage(MSG
* Msg
, BOOL
* RemoveMessages
, BOOL
* NotForUs
, UINT first
, UINT last
)
1865 if ( IS_MOUSE_MESSAGE(Msg
->message
))
1867 return co_IntProcessMouseMessage(Msg
, RemoveMessages
, NotForUs
, first
, last
);
1869 else if ( IS_KBD_MESSAGE(Msg
->message
))
1871 return co_IntProcessKeyboardMessage(Msg
, RemoveMessages
);
1877 /* check whether a message filter contains at least one potential hardware message */
1879 filter_contains_hw_range( UINT first
, UINT last
)
1881 /* hardware message ranges are (in numerical order):
1882 * WM_NCMOUSEFIRST .. WM_NCMOUSELAST
1883 * WM_KEYFIRST .. WM_KEYLAST
1884 * WM_MOUSEFIRST .. WM_MOUSELAST
1887 if (last
< WM_NCMOUSEFIRST
) return 0;
1888 if (first
> WM_NCMOUSELAST
&& last
< WM_KEYFIRST
) return 0;
1889 if (first
> WM_KEYLAST
&& last
< WM_MOUSEFIRST
) return 0;
1890 if (first
> WM_MOUSELAST
) return 0;
1895 co_MsqPeekHardwareMessage(IN PTHREADINFO pti
,
1898 IN UINT MsgFilterLow
,
1899 IN UINT MsgFilterHigh
,
1903 BOOL AcceptMessage
, NotForUs
;
1904 PUSER_MESSAGE CurrentMessage
;
1905 PLIST_ENTRY ListHead
;
1910 PUSER_MESSAGE_QUEUE MessageQueue
= pti
->MessageQueue
;
1912 if (!filter_contains_hw_range( MsgFilterLow
, MsgFilterHigh
)) return FALSE
;
1914 ListHead
= MessageQueue
->HardwareMessagesListHead
.Flink
;
1916 if (IsListEmpty(ListHead
)) return FALSE
;
1918 if (!MessageQueue
->ptiSysLock
)
1920 MessageQueue
->ptiSysLock
= pti
;
1921 pti
->pcti
->CTI_flags
|= CTI_THREADSYSLOCK
;
1924 if (MessageQueue
->ptiSysLock
!= pti
)
1926 ERR("Thread Q is locked to ptiSysLock 0x%p pti 0x%p\n",MessageQueue
->ptiSysLock
,pti
);
1930 while (ListHead
!= &MessageQueue
->HardwareMessagesListHead
)
1932 CurrentMessage
= CONTAINING_RECORD(ListHead
, USER_MESSAGE
, ListEntry
);
1933 ListHead
= ListHead
->Flink
;
1935 if (MessageQueue
->idSysPeek
== (ULONG_PTR
)CurrentMessage
)
1937 TRACE("Skip this message due to it is in play!\n");
1942 1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL.
1943 2: retrieves only messages on the current thread's message queue whose hwnd value is NULL.
1944 3: handle to the window whose messages are to be retrieved.
1946 if ( ( !Window
|| // 1
1947 ( Window
== PWND_BOTTOM
&& CurrentMessage
->Msg
.hwnd
== NULL
) || // 2
1948 ( Window
!= PWND_BOTTOM
&& Window
->head
.h
== CurrentMessage
->Msg
.hwnd
) || // 3
1949 ( CurrentMessage
->Msg
.message
== WM_MOUSEMOVE
) ) && // Null window for mouse moves.
1950 ( ( ( MsgFilterLow
== 0 && MsgFilterHigh
== 0 ) && CurrentMessage
->QS_Flags
& QSflags
) ||
1951 ( MsgFilterLow
<= CurrentMessage
->Msg
.message
&& MsgFilterHigh
>= CurrentMessage
->Msg
.message
) ) )
1953 idSave
= MessageQueue
->idSysPeek
;
1954 MessageQueue
->idSysPeek
= (ULONG_PTR
)CurrentMessage
;
1956 msg
= CurrentMessage
->Msg
;
1957 QS_Flags
= CurrentMessage
->QS_Flags
;
1961 UpdateKeyStateFromMsg(MessageQueue
, &msg
);
1962 AcceptMessage
= co_IntProcessHardwareMessage(&msg
, &Remove
, &NotForUs
, MsgFilterLow
, MsgFilterHigh
);
1966 if (CurrentMessage
->pti
!= NULL
)
1968 RemoveEntryList(&CurrentMessage
->ListEntry
);
1969 MsqDestroyMessage(CurrentMessage
);
1971 ClearMsgBitsMask(pti
, QS_Flags
);
1974 MessageQueue
->idSysPeek
= idSave
;
1985 // Fix all but one wine win:test_GetMessagePos WM_TIMER tests. See PostTimerMessages.
1986 if (!RtlEqualMemory(&pti
->ptLast
, &msg
.pt
, sizeof(POINT
)))
1988 pti
->TIF_flags
|= TIF_MSGPOSCHANGED
;
1990 pti
->ptLast
= msg
.pt
;
1991 pti
->timeLast
= msg
.time
;
1992 //MessageQueue->ExtraInfo = ExtraInfo;
1999 MessageQueue
->ptiSysLock
= NULL
;
2000 pti
->pcti
->CTI_flags
&= ~CTI_THREADSYSLOCK
;
2005 MsqPeekMessage(IN PTHREADINFO pti
,
2008 IN UINT MsgFilterLow
,
2009 IN UINT MsgFilterHigh
,
2011 OUT LONG_PTR
*ExtraInfo
,
2014 PUSER_MESSAGE CurrentMessage
;
2015 PLIST_ENTRY ListHead
;
2019 ListHead
= pti
->PostedMessagesListHead
.Flink
;
2021 if (IsListEmpty(ListHead
)) return FALSE
;
2023 while(ListHead
!= &pti
->PostedMessagesListHead
)
2025 CurrentMessage
= CONTAINING_RECORD(ListHead
, USER_MESSAGE
, ListEntry
);
2026 ListHead
= ListHead
->Flink
;
2029 1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL.
2030 2: retrieves only messages on the current thread's message queue whose hwnd value is NULL.
2031 3: handle to the window whose messages are to be retrieved.
2033 if ( ( !Window
|| // 1
2034 ( Window
== PWND_BOTTOM
&& CurrentMessage
->Msg
.hwnd
== NULL
) || // 2
2035 ( Window
!= PWND_BOTTOM
&& Window
->head
.h
== CurrentMessage
->Msg
.hwnd
) ) && // 3
2036 ( ( ( MsgFilterLow
== 0 && MsgFilterHigh
== 0 ) && CurrentMessage
->QS_Flags
& QSflags
) ||
2037 ( MsgFilterLow
<= CurrentMessage
->Msg
.message
&& MsgFilterHigh
>= CurrentMessage
->Msg
.message
) ) )
2039 *Message
= CurrentMessage
->Msg
;
2040 *ExtraInfo
= CurrentMessage
->ExtraInfo
;
2041 QS_Flags
= CurrentMessage
->QS_Flags
;
2045 if (CurrentMessage
->pti
!= NULL
)
2047 RemoveEntryList(&CurrentMessage
->ListEntry
);
2048 MsqDestroyMessage(CurrentMessage
);
2050 ClearMsgBitsMask(pti
, QS_Flags
);
2061 co_MsqWaitForNewMessages(PTHREADINFO pti
, PWND WndFilter
,
2062 UINT MsgFilterMin
, UINT MsgFilterMax
)
2064 NTSTATUS ret
= STATUS_SUCCESS
;
2066 // Post mouse moves before waiting for messages.
2067 if (pti
->MessageQueue
->QF_flags
& QF_MOUSEMOVED
)
2069 IntCoalesceMouseMove(pti
);
2074 ZwYieldExecution(); // Let someone else run!
2076 ret
= KeWaitForSingleObject( pti
->pEventQueueServer
,
2082 if ( ret
== STATUS_USER_APC
)
2084 TRACE("MWFNW User APC\n");
2085 co_IntDeliverUserAPC();
2091 MsqIsHung(PTHREADINFO pti
)
2093 LARGE_INTEGER LargeTickCount
;
2095 KeQueryTickCount(&LargeTickCount
);
2097 if ((LargeTickCount
.u
.LowPart
- pti
->timeLast
) > MSQ_HUNG
&&
2098 !(pti
->pcti
->fsWakeMask
& QS_INPUT
) &&
2099 !PsGetThreadFreezeCount(pti
->pEThread
) &&
2100 !(pti
->ppi
->W32PF_flags
& W32PF_APPSTARTING
))
2107 IsThreadSuspended(PTHREADINFO pti
)
2112 ObReferenceObject(pti
->pEThread
);
2113 if (!(pti
->pEThread
->Tcb
.SuspendCount
) && !PsGetThreadFreezeCount(pti
->pEThread
)) Ret
= FALSE
;
2114 ObDereferenceObject(pti
->pEThread
);
2122 HungAppSysTimerProc(HWND hwnd
, UINT uMsg
, UINT_PTR idEvent
, DWORD dwTime
)
2125 TRACE("HungAppSysTimerProc\n");
2126 // Process list of windows that are hung and waiting.
2130 MsqInitializeMessageQueue(PTHREADINFO pti
, PUSER_MESSAGE_QUEUE MessageQueue
)
2132 InitializeListHead(&MessageQueue
->HardwareMessagesListHead
); // Keep here!
2133 MessageQueue
->spwndFocus
= NULL
;
2134 MessageQueue
->iCursorLevel
= 0;
2135 MessageQueue
->CursorObject
= SYSTEMCUR(WAIT
); // See test_initial_cursor.
2136 if (MessageQueue
->CursorObject
)
2138 TRACE("Default cursor hcur %p\n",UserHMGetHandle(MessageQueue
->CursorObject
));
2139 UserReferenceObject(MessageQueue
->CursorObject
);
2141 RtlCopyMemory(MessageQueue
->afKeyState
, gafAsyncKeyState
, sizeof(gafAsyncKeyState
));
2142 MessageQueue
->ptiMouse
= pti
;
2143 MessageQueue
->ptiKeyboard
= pti
;
2144 MessageQueue
->cThreads
++;
2150 MsqCleanupThreadMsgs(PTHREADINFO pti
)
2152 PLIST_ENTRY CurrentEntry
;
2153 PUSER_MESSAGE CurrentMessage
;
2154 PUSER_SENT_MESSAGE CurrentSentMessage
;
2156 TRACE("MsqCleanupThreadMsgs %p\n",pti
);
2158 // Clear it all out.
2161 pti
->pcti
->fsWakeBits
= 0;
2162 pti
->pcti
->fsChangeBits
= 0;
2165 pti
->nCntsQBits
[QSRosKey
] = 0;
2166 pti
->nCntsQBits
[QSRosMouseMove
] = 0;
2167 pti
->nCntsQBits
[QSRosMouseButton
] = 0;
2168 pti
->nCntsQBits
[QSRosPostMessage
] = 0;
2169 pti
->nCntsQBits
[QSRosSendMessage
] = 0;
2170 pti
->nCntsQBits
[QSRosHotKey
] = 0;
2171 pti
->nCntsQBits
[QSRosEvent
] = 0;
2173 /* cleanup posted messages */
2174 while (!IsListEmpty(&pti
->PostedMessagesListHead
))
2176 CurrentEntry
= RemoveHeadList(&pti
->PostedMessagesListHead
);
2177 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
, ListEntry
);
2178 if (CurrentMessage
->dwQEvent
)
2180 if (CurrentMessage
->dwQEvent
== POSTEVENT_NWE
)
2182 ExFreePoolWithTag( (PVOID
)CurrentMessage
->ExtraInfo
, TAG_HOOK
);
2185 MsqDestroyMessage(CurrentMessage
);
2188 /* remove the messages that have not yet been dispatched */
2189 while (!IsListEmpty(&pti
->SentMessagesListHead
))
2191 CurrentEntry
= pti
->SentMessagesListHead
.Flink
;
2192 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
, ListEntry
);
2194 ERR("Thread Cleanup Sent Messages %p\n",CurrentSentMessage
);
2196 /* wake the sender's thread */
2197 if (CurrentSentMessage
->pkCompletionEvent
!= NULL
)
2199 KeSetEvent(CurrentSentMessage
->pkCompletionEvent
, IO_NO_INCREMENT
, FALSE
);
2202 if (CurrentSentMessage
->HasPackedLParam
)
2204 if (CurrentSentMessage
->Msg
.lParam
)
2205 ExFreePool((PVOID
)CurrentSentMessage
->Msg
.lParam
);
2208 /* free the message */
2209 FreeUserMessage(CurrentSentMessage
);
2212 // Process Trouble Message List
2213 if (!IsListEmpty(&usmList
))
2215 CurrentEntry
= usmList
.Flink
;
2216 while (CurrentEntry
!= &usmList
)
2218 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
, ListEntry
);
2219 CurrentEntry
= CurrentEntry
->Flink
;
2221 TRACE("Found troubled messages %p on the list\n",CurrentSentMessage
);
2223 if ( pti
== CurrentSentMessage
->ptiReceiver
)
2225 if (CurrentSentMessage
->HasPackedLParam
)
2227 if (CurrentSentMessage
->Msg
.lParam
)
2228 ExFreePool((PVOID
)CurrentSentMessage
->Msg
.lParam
);
2231 /* free the message */
2232 FreeUserMessage(CurrentSentMessage
);
2234 else if ( pti
== CurrentSentMessage
->ptiSender
||
2235 pti
== CurrentSentMessage
->ptiCallBackSender
)
2237 // Determine whether this message is being processed or not.
2238 if ((CurrentSentMessage
->flags
& (SMF_RECEIVERBUSY
|SMF_RECEIVEDMESSAGE
)) != SMF_RECEIVEDMESSAGE
)
2240 CurrentSentMessage
->flags
|= SMF_RECEIVERFREE
;
2243 if (!(CurrentSentMessage
->flags
& SMF_RECEIVERFREE
))
2246 if (CurrentSentMessage
->HasPackedLParam
)
2248 if (CurrentSentMessage
->Msg
.lParam
)
2249 ExFreePool((PVOID
)CurrentSentMessage
->Msg
.lParam
);
2252 /* free the message */
2253 FreeUserMessage(CurrentSentMessage
);
2261 MsqCleanupMessageQueue(PTHREADINFO pti
)
2263 PUSER_MESSAGE_QUEUE MessageQueue
;
2265 MessageQueue
= pti
->MessageQueue
;
2266 MessageQueue
->cThreads
--;
2268 if (MessageQueue
->cThreads
)
2270 if (MessageQueue
->ptiSysLock
== pti
) MessageQueue
->ptiSysLock
= NULL
;
2273 if (MessageQueue
->CursorObject
)
2275 PCURICON_OBJECT pCursor
= MessageQueue
->CursorObject
;
2277 /* Change to another cursor if we going to dereference current one
2278 Note: we can't use UserSetCursor because it uses current thread
2279 message queue instead of queue given for cleanup */
2280 if (IntGetSysCursorInfo()->CurrentCursorObject
== pCursor
)
2284 /* Get the screen DC */
2285 hdcScreen
= IntGetScreenDC();
2287 GreMovePointer(hdcScreen
, -1, -1);
2288 IntGetSysCursorInfo()->CurrentCursorObject
= NULL
;
2291 TRACE("DereferenceObject pCursor\n");
2292 UserDereferenceObject(pCursor
);
2295 if (gpqForeground
== MessageQueue
)
2297 IntSetFocusMessageQueue(NULL
);
2299 if (gpqForegroundPrev
== MessageQueue
)
2301 gpqForegroundPrev
= NULL
;
2303 if (gpqCursor
== MessageQueue
)
2309 PUSER_MESSAGE_QUEUE FASTCALL
2310 MsqCreateMessageQueue(PTHREADINFO pti
)
2312 PUSER_MESSAGE_QUEUE MessageQueue
;
2314 MessageQueue
= ExAllocatePoolWithTag(NonPagedPool
,
2315 sizeof(*MessageQueue
),
2323 RtlZeroMemory(MessageQueue
, sizeof(*MessageQueue
));
2324 /* hold at least one reference until it'll be destroyed */
2325 IntReferenceMessageQueue(MessageQueue
);
2326 /* initialize the queue */
2327 if (!MsqInitializeMessageQueue(pti
, MessageQueue
))
2329 IntDereferenceMessageQueue(MessageQueue
);
2333 return MessageQueue
;
2337 MsqDestroyMessageQueue(_In_ PTHREADINFO pti
)
2340 PUSER_MESSAGE_QUEUE MessageQueue
= pti
->MessageQueue
;
2342 NT_ASSERT(MessageQueue
!= NULL
);
2343 MessageQueue
->QF_flags
|= QF_INDESTROY
;
2345 /* remove the message queue from any desktops */
2346 if ((desk
= InterlockedExchangePointer((PVOID
*)&MessageQueue
->Desktop
, 0)))
2348 (void)InterlockedExchangePointer((PVOID
*)&desk
->ActiveMessageQueue
, 0);
2349 IntDereferenceMessageQueue(MessageQueue
);
2353 MsqCleanupMessageQueue(pti
);
2355 /* decrease the reference counter, if it hits zero, the queue will be freed */
2356 _PRAGMA_WARNING_SUPPRESS(__WARNING_USING_UNINIT_VAR
);
2357 IntDereferenceMessageQueue(MessageQueue
);
2361 MsqSetMessageExtraInfo(LPARAM lParam
)
2365 PUSER_MESSAGE_QUEUE MessageQueue
;
2367 pti
= PsGetCurrentThreadWin32Thread();
2368 MessageQueue
= pti
->MessageQueue
;
2374 Ret
= MessageQueue
->ExtraInfo
;
2375 MessageQueue
->ExtraInfo
= lParam
;
2381 MsqGetMessageExtraInfo(VOID
)
2384 PUSER_MESSAGE_QUEUE MessageQueue
;
2386 pti
= PsGetCurrentThreadWin32Thread();
2387 MessageQueue
= pti
->MessageQueue
;
2393 return MessageQueue
->ExtraInfo
;
2396 // ReplyMessage is called by the thread receiving the window message.
2398 co_MsqReplyMessage( LRESULT lResult
)
2400 PUSER_SENT_MESSAGE Message
;
2403 pti
= PsGetCurrentThreadWin32Thread();
2404 Message
= pti
->pusmCurrent
;
2406 if (!Message
) return FALSE
;
2408 if (Message
->QS_Flags
& QS_SMRESULT
) return FALSE
;
2410 // SendMessageXxx || Callback msg and not a notify msg
2411 if (Message
->ptiSender
|| Message
->CompletionCallback
)
2413 Message
->lResult
= lResult
;
2414 Message
->QS_Flags
|= QS_SMRESULT
;
2415 // See co_MsqDispatchOneSentMessage, change bits already accounted for and cleared and this msg is going away..
2421 MsqSetStateWindow(PTHREADINFO pti
, ULONG Type
, HWND hWnd
)
2424 PUSER_MESSAGE_QUEUE MessageQueue
;
2426 MessageQueue
= pti
->MessageQueue
;
2430 case MSQ_STATE_CAPTURE
:
2431 Prev
= MessageQueue
->spwndCapture
? UserHMGetHandle(MessageQueue
->spwndCapture
) : 0;
2432 MessageQueue
->spwndCapture
= ValidateHwndNoErr(hWnd
);
2434 case MSQ_STATE_ACTIVE
:
2435 Prev
= MessageQueue
->spwndActive
? UserHMGetHandle(MessageQueue
->spwndActive
) : 0;
2436 MessageQueue
->spwndActive
= ValidateHwndNoErr(hWnd
);
2438 case MSQ_STATE_FOCUS
:
2439 Prev
= MessageQueue
->spwndFocus
? UserHMGetHandle(MessageQueue
->spwndFocus
) : 0;
2440 MessageQueue
->spwndFocus
= ValidateHwndNoErr(hWnd
);
2442 case MSQ_STATE_MENUOWNER
:
2443 Prev
= MessageQueue
->MenuOwner
;
2444 MessageQueue
->MenuOwner
= hWnd
;
2446 case MSQ_STATE_MOVESIZE
:
2447 Prev
= MessageQueue
->MoveSize
;
2448 MessageQueue
->MoveSize
= hWnd
;
2450 case MSQ_STATE_CARET
:
2451 Prev
= MessageQueue
->CaretInfo
.hWnd
;
2452 MessageQueue
->CaretInfo
.hWnd
= hWnd
;
2461 NtUserGetKeyState(INT key
)
2467 Ret
= UserGetKeyState(key
);
2477 NtUserGetKeyboardState(LPBYTE lpKeyState
)
2479 DWORD i
, ret
= TRUE
;
2481 PUSER_MESSAGE_QUEUE MessageQueue
;
2485 pti
= PsGetCurrentThreadWin32Thread();
2486 MessageQueue
= pti
->MessageQueue
;
2490 /* Probe and copy key state to an array */
2491 ProbeForWrite(lpKeyState
, 256 * sizeof(BYTE
), 1);
2492 for (i
= 0; i
< 256; ++i
)
2495 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, i
))
2496 lpKeyState
[i
] |= KS_DOWN_BIT
;
2497 if (IS_KEY_LOCKED(MessageQueue
->afKeyState
, i
))
2498 lpKeyState
[i
] |= KS_LOCK_BIT
;
2501 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2503 SetLastNtError(_SEH2_GetExceptionCode());
2515 NtUserSetKeyboardState(LPBYTE pKeyState
)
2520 PUSER_MESSAGE_QUEUE MessageQueue
;
2522 UserEnterExclusive();
2524 pti
= PsGetCurrentThreadWin32Thread();
2525 MessageQueue
= pti
->MessageQueue
;
2529 ProbeForRead(pKeyState
, 256 * sizeof(BYTE
), 1);
2530 for (i
= 0; i
< 256; ++i
)
2532 SET_KEY_DOWN(MessageQueue
->afKeyState
, i
, pKeyState
[i
] & KS_DOWN_BIT
);
2533 SET_KEY_LOCKED(MessageQueue
->afKeyState
, i
, pKeyState
[i
] & KS_LOCK_BIT
);
2536 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2538 SetLastNtError(_SEH2_GetExceptionCode());