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
)
554 LARGE_INTEGER LargeTickCount
;
556 // Force time stamp to update, keeping message time in sync.
557 if (gdwMouseMoveTimeStamp
== 0)
559 KeQueryTickCount(&LargeTickCount
);
560 gdwMouseMoveTimeStamp
= MsqCalculateMessageTime(&LargeTickCount
);
563 // Build mouse move message.
565 Msg
.message
= WM_MOUSEMOVE
;
567 Msg
.lParam
= MAKELONG(gpsi
->ptCursor
.x
, gpsi
->ptCursor
.y
);
568 Msg
.time
= gdwMouseMoveTimeStamp
;
569 Msg
.pt
= gpsi
->ptCursor
;
572 MsqPostMouseMove(pti
, &Msg
, gdwMouseMoveExtraInfo
);
574 // Zero the time stamp.
575 gdwMouseMoveTimeStamp
= 0;
577 // Clear flag since the move was posted.
578 pti
->MessageQueue
->QF_flags
&= ~QF_MOUSEMOVED
;
582 co_MsqInsertMouseMessage(MSG
* Msg
, DWORD flags
, ULONG_PTR dwExtraInfo
, BOOL Hook
)
584 LARGE_INTEGER LargeTickCount
;
585 MSLLHOOKSTRUCT MouseHookData
;
587 PWND pwnd
, pwndDesktop
;
590 PUSER_MESSAGE_QUEUE MessageQueue
;
591 PSYSTEM_CURSORINFO CurInfo
;
593 KeQueryTickCount(&LargeTickCount
);
594 Msg
->time
= MsqCalculateMessageTime(&LargeTickCount
);
596 MouseHookData
.pt
.x
= LOWORD(Msg
->lParam
);
597 MouseHookData
.pt
.y
= HIWORD(Msg
->lParam
);
598 switch (Msg
->message
)
601 MouseHookData
.mouseData
= MAKELONG(0, GET_WHEEL_DELTA_WPARAM(Msg
->wParam
));
605 case WM_XBUTTONDBLCLK
:
606 case WM_NCXBUTTONDOWN
:
608 case WM_NCXBUTTONDBLCLK
:
609 MouseHookData
.mouseData
= MAKELONG(0, HIWORD(Msg
->wParam
));
612 MouseHookData
.mouseData
= 0;
616 MouseHookData
.flags
= flags
; // LLMHF_INJECTED
617 MouseHookData
.time
= Msg
->time
;
618 MouseHookData
.dwExtraInfo
= dwExtraInfo
;
620 /* If the hook procedure returned non zero, dont send the message */
623 if (co_HOOK_CallHooks(WH_MOUSE_LL
, HC_ACTION
, Msg
->message
, (LPARAM
) &MouseHookData
))
627 /* Get the desktop window */
628 pwndDesktop
= UserGetDesktopWindow();
629 if (!pwndDesktop
) return;
630 // pDesk = pwndDesktop->head.rpdesk;
632 /* Check if the mouse is captured */
633 Msg
->hwnd
= IntGetCaptureWindow();
634 if (Msg
->hwnd
!= NULL
)
636 pwnd
= UserGetWindowObject(Msg
->hwnd
);
640 pwnd
= IntTopLevelWindowFromPoint(Msg
->pt
.x
, Msg
->pt
.y
);
641 if (pwnd
) Msg
->hwnd
= pwnd
->head
.h
;
644 hdcScreen
= IntGetScreenDC();
645 CurInfo
= IntGetSysCursorInfo();
647 /* Check if we found a window */
648 if (Msg
->hwnd
!= NULL
&& pwnd
!= NULL
)
650 pti
= pwnd
->head
.pti
;
651 MessageQueue
= pti
->MessageQueue
;
653 if (MessageQueue
->QF_flags
& QF_INDESTROY
)
655 ERR("Mouse is over a Window with a Dead Message Queue!\n");
659 // Check to see if this is attached.
660 if ( pti
!= MessageQueue
->ptiMouse
&&
661 MessageQueue
->cThreads
> 1 )
663 // Set the send pti to the message queue mouse pti.
664 pti
= MessageQueue
->ptiMouse
;
667 if (Msg
->message
== WM_MOUSEMOVE
)
669 /* Check if cursor should be visible */
671 MessageQueue
->CursorObject
&&
672 MessageQueue
->iCursorLevel
>= 0)
674 /* Check if shape has changed */
675 if(CurInfo
->CurrentCursorObject
!= MessageQueue
->CursorObject
)
677 /* Call GDI to set the new screen cursor */
678 GreSetPointerShape(hdcScreen
,
679 MessageQueue
->CursorObject
->hbmAlpha
?
680 NULL
: MessageQueue
->CursorObject
->hbmMask
,
681 MessageQueue
->CursorObject
->hbmAlpha
?
682 MessageQueue
->CursorObject
->hbmAlpha
: MessageQueue
->CursorObject
->hbmColor
,
683 MessageQueue
->CursorObject
->xHotspot
,
684 MessageQueue
->CursorObject
->yHotspot
,
687 MessageQueue
->CursorObject
->hbmAlpha
? SPS_ALPHA
: 0);
690 GreMovePointer(hdcScreen
, Msg
->pt
.x
, Msg
->pt
.y
);
692 /* Check if we have to hide cursor */
693 else if (CurInfo
->ShowingCursor
>= 0)
694 GreMovePointer(hdcScreen
, -1, -1);
696 /* Update global cursor info */
697 CurInfo
->ShowingCursor
= MessageQueue
->iCursorLevel
;
698 CurInfo
->CurrentCursorObject
= MessageQueue
->CursorObject
;
699 gpqCursor
= MessageQueue
;
701 /* Mouse move is a special case */
702 MessageQueue
->QF_flags
|= QF_MOUSEMOVED
;
703 gdwMouseMoveExtraInfo
= dwExtraInfo
;
704 gdwMouseMoveTimeStamp
= Msg
->time
;
705 MsqWakeQueue(pti
, QS_MOUSEMOVE
, TRUE
);
709 if (!IntGetCaptureWindow())
711 // ERR("ptiLastInput is set\n");
712 // ptiLastInput = pti; // Once this is set during Reboot or Shutdown, this prevents the exit window having foreground.
713 // Find all the Move Mouse calls and fix mouse set active focus issues......
716 // Post mouse move before posting mouse buttons, keep it in sync.
717 if (pti
->MessageQueue
->QF_flags
& QF_MOUSEMOVED
)
719 IntCoalesceMouseMove(pti
);
722 TRACE("Posting mouse message to hwnd=%p!\n", UserHMGetHandle(pwnd
));
723 MsqPostMessage(pti
, Msg
, TRUE
, QS_MOUSEBUTTON
, 0, dwExtraInfo
);
728 /* always show cursor on background; FIXME: set default pointer */
729 GreMovePointer(hdcScreen
, Msg
->pt
.x
, Msg
->pt
.y
);
730 CurInfo
->ShowingCursor
= 0;
734 PUSER_MESSAGE FASTCALL
735 MsqCreateMessage(LPMSG Msg
)
737 PUSER_MESSAGE Message
;
739 Message
= ExAllocateFromPagedLookasideList(pgMessageLookasideList
);
745 RtlZeroMemory(Message
, sizeof(*Message
));
746 RtlMoveMemory(&Message
->Msg
, Msg
, sizeof(MSG
));
752 MsqDestroyMessage(PUSER_MESSAGE Message
)
754 TRACE("Post Destroy %d\n",PostMsgCount
)
755 if (Message
->pti
== NULL
)
757 ERR("Double Free Message\n");
760 RemoveEntryList(&Message
->ListEntry
);
762 ExFreeToPagedLookasideList(pgMessageLookasideList
, Message
);
766 PUSER_SENT_MESSAGE FASTCALL
767 AllocateUserMessage(BOOL KEvent
)
769 PUSER_SENT_MESSAGE Message
;
771 if(!(Message
= ExAllocateFromPagedLookasideList(pgSendMsgLookasideList
)))
773 ERR("AllocateUserMessage(): Not enough memory to allocate a message");
776 RtlZeroMemory(Message
, sizeof(USER_SENT_MESSAGE
));
780 Message
->pkCompletionEvent
= &Message
->CompletionEvent
;
782 KeInitializeEvent(Message
->pkCompletionEvent
, NotificationEvent
, FALSE
);
785 TRACE("AUM pti %p msg %p\n",PsGetCurrentThreadWin32Thread(),Message
);
790 FreeUserMessage(PUSER_SENT_MESSAGE Message
)
792 Message
->pkCompletionEvent
= NULL
;
794 /* Remove it from the list */
795 RemoveEntryList(&Message
->ListEntry
);
797 ExFreeToPagedLookasideList(pgSendMsgLookasideList
, Message
);
802 MsqRemoveWindowMessagesFromQueue(PWND Window
)
805 PUSER_SENT_MESSAGE SentMessage
;
806 PUSER_MESSAGE PostedMessage
;
807 PLIST_ENTRY CurrentEntry
, ListHead
;
811 pti
= Window
->head
.pti
;
813 /* remove the posted messages for this window */
814 CurrentEntry
= pti
->PostedMessagesListHead
.Flink
;
815 ListHead
= &pti
->PostedMessagesListHead
;
816 while (CurrentEntry
!= ListHead
)
818 PostedMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
, ListEntry
);
820 if (PostedMessage
->Msg
.hwnd
== Window
->head
.h
)
822 if (PostedMessage
->Msg
.message
== WM_QUIT
&& pti
->QuitPosted
== 0)
825 pti
->exitCode
= PostedMessage
->Msg
.wParam
;
827 ClearMsgBitsMask(pti
, PostedMessage
->QS_Flags
);
828 MsqDestroyMessage(PostedMessage
);
829 CurrentEntry
= pti
->PostedMessagesListHead
.Flink
;
833 CurrentEntry
= CurrentEntry
->Flink
;
837 /* remove the sent messages for this window */
838 CurrentEntry
= pti
->SentMessagesListHead
.Flink
;
839 ListHead
= &pti
->SentMessagesListHead
;
840 while (CurrentEntry
!= ListHead
)
842 SentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
, ListEntry
);
844 if(SentMessage
->Msg
.hwnd
== Window
->head
.h
)
846 ERR("Remove Window Messages %p From Sent Queue\n",SentMessage
);
847 #if 0 // Should mark these as invalid and allow the rest clean up, so far no harm by just commenting out. See CORE-9210.
848 ClearMsgBitsMask(pti
, SentMessage
->QS_Flags
);
850 /* wake the sender's thread */
851 if (SentMessage
->pkCompletionEvent
!= NULL
)
853 KeSetEvent(SentMessage
->pkCompletionEvent
, IO_NO_INCREMENT
, FALSE
);
856 if (SentMessage
->HasPackedLParam
)
858 if (SentMessage
->Msg
.lParam
)
859 ExFreePool((PVOID
)SentMessage
->Msg
.lParam
);
862 /* free the message */
863 FreeUserMessage(SentMessage
);
865 CurrentEntry
= pti
->SentMessagesListHead
.Flink
;
867 CurrentEntry
= CurrentEntry
->Flink
;
871 CurrentEntry
= CurrentEntry
->Flink
;
877 co_MsqDispatchOneSentMessage(
878 _In_ PTHREADINFO pti
)
880 PUSER_SENT_MESSAGE SaveMsg
, Message
;
885 ASSERT(pti
== PsGetCurrentThreadWin32Thread());
887 if (IsListEmpty(&pti
->SentMessagesListHead
))
892 /* remove it from the list of pending messages */
893 Entry
= RemoveHeadList(&pti
->SentMessagesListHead
);
894 Message
= CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
);
896 // Signal this message is being processed.
897 Message
->flags
|= SMF_RECEIVERBUSY
|SMF_RECEIVEDMESSAGE
;
899 SaveMsg
= pti
->pusmCurrent
;
900 pti
->pusmCurrent
= Message
;
902 // Processing a message sent to it from another thread.
903 if ( ( Message
->ptiSender
&& pti
!= Message
->ptiSender
) ||
904 ( Message
->ptiCallBackSender
&& pti
!= Message
->ptiCallBackSender
))
905 { // most likely, but, to be sure.
906 pti
->pcti
->CTI_flags
|= CTI_INSENDMESSAGE
; // Let the user know...
909 /* Now insert it to the global list of messages that can be removed Justin Case there's Trouble */
910 InsertTailList(&usmList
, &Message
->ListEntry
);
912 ClearMsgBitsMask(pti
, Message
->QS_Flags
);
914 if (Message
->HookMessage
== MSQ_ISHOOK
)
915 { // Direct Hook Call processor
916 Result
= co_CallHook( Message
->Msg
.message
, // HookId
917 (INT
)(INT_PTR
)Message
->Msg
.hwnd
, // Code
919 Message
->Msg
.lParam
);
921 else if(Message
->HookMessage
== MSQ_INJECTMODULE
)
923 Result
= IntLoadHookModule(Message
->Msg
.message
,
924 (HHOOK
)Message
->Msg
.lParam
,
925 Message
->Msg
.wParam
);
927 else if ((Message
->CompletionCallback
) &&
928 (Message
->ptiCallBackSender
== pti
))
929 { /* Call the callback routine */
930 if (Message
->QS_Flags
& QS_SMRESULT
)
932 co_IntCallSentMessageCallback(Message
->CompletionCallback
,
934 Message
->Msg
.message
,
935 Message
->CompletionCallbackContext
,
937 /* Set callback to NULL to prevent reentry */
938 Message
->CompletionCallback
= NULL
;
942 /* The message has not been processed yet, reinsert it. */
943 RemoveEntryList(&Message
->ListEntry
);
944 InsertTailList(&Message
->ptiCallBackSender
->SentMessagesListHead
, &Message
->ListEntry
);
945 // List is occupied need to set the bit.
946 MsqWakeQueue(Message
->ptiCallBackSender
, QS_SENDMESSAGE
, TRUE
);
947 ERR("Callback Message not processed yet. Requeuing the message\n"); //// <---- Need to see if this happens.
953 { /* Call the window procedure. */
954 Result
= co_IntSendMessage( Message
->Msg
.hwnd
,
955 Message
->Msg
.message
,
957 Message
->Msg
.lParam
);
960 /* If the message is a callback, insert it in the callback senders MessageQueue */
961 if (Message
->CompletionCallback
)
963 if (Message
->ptiCallBackSender
)
965 Message
->lResult
= Result
;
966 Message
->QS_Flags
|= QS_SMRESULT
;
968 /* insert it in the callers message queue */
969 RemoveEntryList(&Message
->ListEntry
);
970 InsertTailList(&Message
->ptiCallBackSender
->SentMessagesListHead
, &Message
->ListEntry
);
971 MsqWakeQueue(Message
->ptiCallBackSender
, QS_SENDMESSAGE
, TRUE
);
977 // Retrieve the result from callback.
978 if (Message
->QS_Flags
& QS_SMRESULT
)
980 Result
= Message
->lResult
;
983 /* Let the sender know the result. */
984 Message
->lResult
= Result
;
986 if (Message
->HasPackedLParam
)
988 if (Message
->Msg
.lParam
)
989 ExFreePool((PVOID
)Message
->Msg
.lParam
);
992 // Clear busy signal.
993 Message
->flags
&= ~SMF_RECEIVERBUSY
;
995 /* Notify the sender. */
996 if (Message
->pkCompletionEvent
!= NULL
)
998 KeSetEvent(Message
->pkCompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1001 /* free the message */
1002 if (Message
->flags
& SMF_RECEIVERFREE
)
1004 TRACE("Receiver Freeing Message %p\n",Message
);
1005 FreeUserMessage(Message
);
1010 /* do not hangup on the user if this is reentering */
1011 if (!SaveMsg
) pti
->pcti
->CTI_flags
&= ~CTI_INSENDMESSAGE
;
1012 pti
->pusmCurrent
= SaveMsg
;
1018 co_MsqSendMessageAsync(PTHREADINFO ptiReceiver
,
1023 SENDASYNCPROC CompletionCallback
,
1024 ULONG_PTR CompletionCallbackContext
,
1025 BOOL HasPackedLParam
,
1029 PTHREADINFO ptiSender
;
1030 PUSER_SENT_MESSAGE Message
;
1032 if(!(Message
= AllocateUserMessage(FALSE
)))
1034 ERR("MsqSendMessageAsync(): Not enough memory to allocate a message");
1038 ptiSender
= PsGetCurrentThreadWin32Thread();
1040 Message
->Msg
.hwnd
= hwnd
;
1041 Message
->Msg
.message
= Msg
;
1042 Message
->Msg
.wParam
= wParam
;
1043 Message
->Msg
.lParam
= lParam
;
1044 Message
->pkCompletionEvent
= NULL
; // No event needed.
1045 Message
->ptiReceiver
= ptiReceiver
;
1046 Message
->ptiCallBackSender
= ptiSender
;
1047 Message
->CompletionCallback
= CompletionCallback
;
1048 Message
->CompletionCallbackContext
= CompletionCallbackContext
;
1049 Message
->HookMessage
= HookMessage
;
1050 Message
->HasPackedLParam
= HasPackedLParam
;
1051 Message
->QS_Flags
= QS_SENDMESSAGE
;
1052 Message
->flags
= SMF_RECEIVERFREE
;
1054 InsertTailList(&ptiReceiver
->SentMessagesListHead
, &Message
->ListEntry
);
1055 MsqWakeQueue(ptiReceiver
, QS_SENDMESSAGE
, TRUE
);
1061 co_MsqSendMessage(PTHREADINFO ptirec
,
1072 PUSER_SENT_MESSAGE SaveMsg
, Message
;
1073 NTSTATUS WaitStatus
;
1074 LARGE_INTEGER Timeout
;
1077 BOOLEAN SwapStateEnabled
;
1078 LRESULT Result
= 0; //// Result could be trashed. ////
1080 pti
= PsGetCurrentThreadWin32Thread();
1081 ASSERT(pti
!= ptirec
);
1082 ASSERT(ptirec
->pcti
); // Send must have a client side to receive it!!!!
1084 /* Don't send from or to a dying thread */
1085 if (pti
->TIF_flags
& TIF_INCLEANUP
|| ptirec
->TIF_flags
& TIF_INCLEANUP
)
1087 // Unless we are dying and need to tell our parents.
1088 if (pti
->TIF_flags
& TIF_INCLEANUP
&& !(ptirec
->TIF_flags
& TIF_INCLEANUP
))
1090 // Parent notify is the big one. Fire and forget!
1091 TRACE("Send message from dying thread %u\n", Msg
);
1092 co_MsqSendMessageAsync(ptirec
, Wnd
, Msg
, wParam
, lParam
, NULL
, 0, FALSE
, HookMessage
);
1094 if (uResult
) *uResult
= -1;
1095 TRACE("MsqSM: Msg %u Current pti %lu or Rec pti %lu\n", Msg
, pti
->TIF_flags
& TIF_INCLEANUP
, ptirec
->TIF_flags
& TIF_INCLEANUP
);
1096 return STATUS_UNSUCCESSFUL
;
1099 if (IsThreadSuspended(ptirec
))
1101 ERR("Sending to Suspended Thread Msg %lx\n",Msg
);
1102 if (uResult
) *uResult
= -1;
1103 return STATUS_UNSUCCESSFUL
;
1106 // Should we do the same for No Wait?
1107 if ( HookMessage
== MSQ_NORMAL
)
1109 pWnd
= ValidateHwndNoErr(Wnd
);
1111 // These can not cross International Border lines!
1112 if ( pti
->ppi
!= ptirec
->ppi
&& pWnd
)
1116 // Handle the special case when working with password transfers across bordering processes.
1118 case EM_SETPASSWORDCHAR
:
1120 // Look for edit controls setup for passwords.
1121 if ( gpsi
->atomSysClass
[ICLS_EDIT
] == pWnd
->pcls
->atomClassName
&& // Use atomNVClassName.
1122 pWnd
->style
& ES_PASSWORD
)
1124 if (uResult
) *uResult
= -1;
1125 ERR("Running across the border without a passport!\n");
1126 EngSetLastError(ERROR_ACCESS_DENIED
);
1127 return STATUS_UNSUCCESSFUL
;
1131 if (uResult
) *uResult
= -1;
1132 ERR("Running across the border without a passport!\n");
1133 return STATUS_UNSUCCESSFUL
;
1137 // These can not cross State lines!
1138 if ( Msg
== WM_CREATE
|| Msg
== WM_NCCREATE
)
1140 if (uResult
) *uResult
= -1;
1141 ERR("Can not tell the other State we have Create!\n");
1142 return STATUS_UNSUCCESSFUL
;
1146 if(!(Message
= AllocateUserMessage(TRUE
)))
1148 ERR("MsqSendMessage(): Not enough memory to allocate a message\n");
1149 if (uResult
) *uResult
= -1;
1150 return STATUS_INSUFFICIENT_RESOURCES
;
1153 Timeout
.QuadPart
= Int32x32To64(-10000,uTimeout
); // Pass SMTO test with a TO of 0x80000000.
1154 TRACE("Timeout val %lld\n",Timeout
.QuadPart
)
1156 Message
->Msg
.hwnd
= Wnd
;
1157 Message
->Msg
.message
= Msg
;
1158 Message
->Msg
.wParam
= wParam
;
1159 Message
->Msg
.lParam
= lParam
;
1160 Message
->ptiReceiver
= ptirec
;
1161 Message
->ptiSender
= pti
;
1162 Message
->HookMessage
= HookMessage
;
1163 Message
->QS_Flags
= QS_SENDMESSAGE
;
1165 SaveMsg
= pti
->pusmSent
;
1166 pti
->pusmSent
= Message
;
1168 /* Queue it in the destination's message queue */
1169 InsertTailList(&ptirec
->SentMessagesListHead
, &Message
->ListEntry
);
1171 MsqWakeQueue(ptirec
, QS_SENDMESSAGE
, TRUE
);
1173 // First time in, turn off swapping of the stack.
1174 if (pti
->cEnterCount
== 0)
1176 SwapStateEnabled
= KeSetKernelStackSwapEnable(FALSE
);
1182 PVOID WaitObjects
[2];
1184 WaitObjects
[0] = Message
->pkCompletionEvent
; // Wait 0
1185 WaitObjects
[1] = ptirec
->pEThread
; // Wait 1
1189 WaitStatus
= KeWaitForMultipleObjects( 2,
1195 (uTimeout
? &Timeout
: NULL
),
1200 if (WaitStatus
== STATUS_TIMEOUT
)
1202 /* Look up if the message has not yet dispatched, if so
1203 make sure it can't pass a result and it must not set the completion event anymore */
1204 Entry
= ptirec
->SentMessagesListHead
.Flink
;
1205 while (Entry
!= &ptirec
->SentMessagesListHead
)
1207 if (CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
) == Message
)
1209 Message
->pkCompletionEvent
= NULL
;
1210 RemoveEntryList(&Message
->ListEntry
);
1211 ClearMsgBitsMask(ptirec
, Message
->QS_Flags
);
1212 InsertTailList(&usmList
, &Message
->ListEntry
);
1215 Entry
= Entry
->Flink
;
1218 ERR("MsqSendMessage (blocked) timed out 1 Status %lx\n", WaitStatus
);
1220 // Receiving thread passed on and left us hanging with issues still pending.
1221 else if (WaitStatus
== STATUS_WAIT_1
)
1223 ERR("Bk Receiving Thread woken up dead!\n");
1224 Message
->flags
|= SMF_RECEIVERDIED
;
1227 while (co_MsqDispatchOneSentMessage(pti
))
1232 PVOID WaitObjects
[3];
1234 WaitObjects
[0] = Message
->pkCompletionEvent
; // Wait 0
1235 WaitObjects
[1] = pti
->pEventQueueServer
; // Wait 1
1236 WaitObjects
[2] = ptirec
->pEThread
; // Wait 2
1242 WaitStatus
= KeWaitForMultipleObjects( 3,
1248 (uTimeout
? &Timeout
: NULL
),
1253 if (WaitStatus
== STATUS_TIMEOUT
)
1255 /* Look up if the message has not yet been dispatched, if so
1256 make sure it can't pass a result and it must not set the completion event anymore */
1257 Entry
= ptirec
->SentMessagesListHead
.Flink
;
1258 while (Entry
!= &ptirec
->SentMessagesListHead
)
1260 if (CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
) == Message
)
1262 Message
->pkCompletionEvent
= NULL
;
1263 RemoveEntryList(&Message
->ListEntry
);
1264 ClearMsgBitsMask(ptirec
, Message
->QS_Flags
);
1265 InsertTailList(&usmList
, &Message
->ListEntry
);
1268 Entry
= Entry
->Flink
;
1271 ERR("MsqSendMessage timed out 2 Status %lx\n", WaitStatus
);
1274 // Receiving thread passed on and left us hanging with issues still pending.
1275 else if (WaitStatus
== STATUS_WAIT_2
)
1277 ERR("NB Receiving Thread woken up dead!\n");
1278 Message
->flags
|= SMF_RECEIVERDIED
;
1282 if (WaitStatus
== STATUS_USER_APC
) break;
1284 while (co_MsqDispatchOneSentMessage(pti
))
1286 } while (WaitStatus
== STATUS_WAIT_1
);
1289 // Count is nil, restore swapping of the stack.
1290 if (--pti
->cEnterCount
== 0 )
1292 KeSetKernelStackSwapEnable(SwapStateEnabled
);
1296 if (WaitStatus
== STATUS_USER_APC
)
1298 // The current thread is dying!
1299 TRACE("User APC\n");
1301 // The Message will be on the Trouble list until Thread cleanup.
1302 Message
->flags
|= SMF_SENDERDIED
;
1304 co_IntDeliverUserAPC();
1305 ERR("User APC Returned\n"); // Should not see this message.
1308 // Force this thread to wake up for the next go around.
1309 KeSetEvent(pti
->pEventQueueServer
, IO_NO_INCREMENT
, FALSE
);
1311 Result
= Message
->lResult
;
1313 // Determine whether this message is being processed or not.
1314 if ((Message
->flags
& (SMF_RECEIVERBUSY
|SMF_RECEIVEDMESSAGE
)) != SMF_RECEIVEDMESSAGE
)
1316 Message
->flags
|= SMF_RECEIVERFREE
;
1319 if (!(Message
->flags
& SMF_RECEIVERFREE
))
1321 TRACE("Sender Freeing Message %p ptirec %p bit %d list empty %d\n",Message
,ptirec
,!!(ptirec
->pcti
->fsChangeBits
& QS_SENDMESSAGE
),IsListEmpty(&ptirec
->SentMessagesListHead
));
1322 // Make it to this point, the message was received.
1323 FreeUserMessage(Message
);
1326 pti
->pusmSent
= SaveMsg
;
1328 TRACE("MSM Allocation Count %d Status %lx Result %d\n",SendMsgCount
,WaitStatus
,Result
);
1330 if (WaitStatus
!= STATUS_TIMEOUT
)
1334 *uResult
= (STATUS_WAIT_0
== WaitStatus
? Result
: 0);
1342 MsqPostMessage(PTHREADINFO pti
,
1344 BOOLEAN HardwareMessage
,
1349 PUSER_MESSAGE Message
;
1350 PUSER_MESSAGE_QUEUE MessageQueue
;
1352 if ( pti
->TIF_flags
& TIF_INCLEANUP
|| pti
->MessageQueue
->QF_flags
& QF_INDESTROY
)
1354 ERR("Post Msg; Thread or Q is Dead!\n");
1358 if(!(Message
= MsqCreateMessage(Msg
)))
1363 MessageQueue
= pti
->MessageQueue
;
1365 if (!HardwareMessage
)
1367 InsertTailList(&pti
->PostedMessagesListHead
, &Message
->ListEntry
);
1371 InsertTailList(&MessageQueue
->HardwareMessagesListHead
, &Message
->ListEntry
);
1374 if (Msg
->message
== WM_HOTKEY
) MessageBits
|= QS_HOTKEY
; // Justin Case, just set it.
1375 Message
->dwQEvent
= dwQEvent
;
1376 Message
->ExtraInfo
= ExtraInfo
;
1377 Message
->QS_Flags
= MessageBits
;
1379 MsqWakeQueue(pti
, MessageBits
, TRUE
);
1380 TRACE("Post Message %d\n",PostMsgCount
);
1384 MsqPostQuitMessage(PTHREADINFO pti
, ULONG ExitCode
)
1386 pti
->QuitPosted
= TRUE
;
1387 pti
->exitCode
= ExitCode
;
1388 MsqWakeQueue(pti
, QS_POSTMESSAGE
|QS_ALLPOSTMESSAGE
, TRUE
);
1391 /***********************************************************************
1392 * MsqSendParentNotify
1394 * Send a WM_PARENTNOTIFY to all ancestors of the given window, unless
1395 * the window has the WS_EX_NOPARENTNOTIFY style.
1397 static void MsqSendParentNotify( PWND pwnd
, WORD event
, WORD idChild
, POINT pt
)
1399 PWND pwndDesktop
= UserGetDesktopWindow();
1401 /* pt has to be in the client coordinates of the parent window */
1402 pt
.x
+= pwndDesktop
->rcClient
.left
- pwnd
->rcClient
.left
;
1403 pt
.y
+= pwndDesktop
->rcClient
.top
- pwnd
->rcClient
.top
;
1409 if (!(pwnd
->style
& WS_CHILD
)) break;
1410 if (pwnd
->ExStyle
& WS_EX_NOPARENTNOTIFY
) break;
1411 if (!(pwndParent
= IntGetParent(pwnd
))) break;
1412 if (pwndParent
== pwndDesktop
) break;
1413 pt
.x
+= pwnd
->rcClient
.left
- pwndParent
->rcClient
.left
;
1414 pt
.y
+= pwnd
->rcClient
.top
- pwndParent
->rcClient
.top
;
1417 co_IntSendMessage( UserHMGetHandle(pwnd
), WM_PARENTNOTIFY
,
1418 MAKEWPARAM( event
, idChild
), MAKELPARAM( pt
.x
, pt
.y
) );
1424 IntTrackMouseMove(PWND pwndTrack
, PDESKTOP pDesk
, PMSG msg
, USHORT hittest
)
1426 // PWND pwndTrack = IntChildrenWindowFromPoint(pwndMsg, msg->pt.x, msg->pt.y);
1427 // hittest = (USHORT)GetNCHitEx(pwndTrack, msg->pt); /// @todo WTF is this???
1429 if ( pDesk
->spwndTrack
!= pwndTrack
|| // Change with tracking window or
1430 msg
->message
!= WM_MOUSEMOVE
|| // Mouse click changes or
1431 pDesk
->htEx
!= hittest
) // Change in current hit test states.
1433 TRACE("ITMM: Track Mouse Move!\n");
1435 /* Handle only the changing window track and mouse move across a border. */
1436 if ( pDesk
->spwndTrack
!= pwndTrack
||
1437 (pDesk
->htEx
== HTCLIENT
) ^ (hittest
== HTCLIENT
) )
1439 TRACE("ITMM: Another Wnd %d or Across Border %d\n",
1440 pDesk
->spwndTrack
!= pwndTrack
,(pDesk
->htEx
== HTCLIENT
) ^ (hittest
== HTCLIENT
));
1442 if ( pDesk
->dwDTFlags
& DF_TME_LEAVE
)
1443 UserPostMessage( UserHMGetHandle(pDesk
->spwndTrack
),
1444 (pDesk
->htEx
!= HTCLIENT
) ? WM_NCMOUSELEAVE
: WM_MOUSELEAVE
,
1447 if ( pDesk
->dwDTFlags
& DF_TME_HOVER
)
1448 IntKillTimer(pDesk
->spwndTrack
, ID_EVENT_SYSTIMER_MOUSEHOVER
, TRUE
);
1450 /* Clear the flags to sign a change. */
1451 pDesk
->dwDTFlags
&= ~(DF_TME_LEAVE
|DF_TME_HOVER
);
1453 /* Set the Track window and hit test. */
1454 pDesk
->spwndTrack
= pwndTrack
;
1455 pDesk
->htEx
= hittest
;
1458 /* Reset, Same Track window, Hover set and Mouse Clicks or Clobbered Hover box. */
1459 if ( pDesk
->spwndTrack
== pwndTrack
&&
1460 ( msg
->message
!= WM_MOUSEMOVE
|| !RECTL_bPointInRect(&pDesk
->rcMouseHover
, msg
->pt
.x
, msg
->pt
.y
)) &&
1461 pDesk
->dwDTFlags
& DF_TME_HOVER
)
1463 TRACE("ITMM: Reset Hover points!\n");
1464 // Restart timer for the hover period.
1465 IntSetTimer(pDesk
->spwndTrack
, ID_EVENT_SYSTIMER_MOUSEHOVER
, pDesk
->dwMouseHoverTime
, SystemTimerProc
, TMRF_SYSTEM
);
1466 // Reset desktop mouse hover from the system default hover rectangle.
1467 RECTL_vSetRect(&pDesk
->rcMouseHover
,
1468 msg
->pt
.x
- gspv
.iMouseHoverWidth
/ 2,
1469 msg
->pt
.y
- gspv
.iMouseHoverHeight
/ 2,
1470 msg
->pt
.x
+ gspv
.iMouseHoverWidth
/ 2,
1471 msg
->pt
.y
+ gspv
.iMouseHoverHeight
/ 2);
1475 BOOL
co_IntProcessMouseMessage(MSG
* msg
, BOOL
* RemoveMessages
, BOOL
* NotForUs
, LONG_PTR ExtraInfo
, UINT first
, UINT last
)
1482 MOUSEHOOKSTRUCT hook
;
1483 BOOL eatMsg
= FALSE
;
1485 PWND pwndMsg
, pwndDesktop
;
1486 PUSER_MESSAGE_QUEUE MessageQueue
;
1488 PSYSTEM_CURSORINFO CurInfo
;
1491 pti
= PsGetCurrentThreadWin32Thread();
1492 pwndDesktop
= UserGetDesktopWindow();
1493 MessageQueue
= pti
->MessageQueue
;
1494 CurInfo
= IntGetSysCursorInfo();
1495 pwndMsg
= ValidateHwndNoErr(msg
->hwnd
);
1496 clk_msg
= MessageQueue
->msgDblClk
;
1497 pDesk
= pwndDesktop
->head
.rpdesk
;
1499 /* find the window to dispatch this mouse message to */
1500 if (MessageQueue
->spwndCapture
)
1503 pwndMsg
= MessageQueue
->spwndCapture
;
1508 Start with null window. See wine win.c:test_mouse_input:WM_COMMAND tests.
1510 pwndMsg
= co_WinPosWindowFromPoint( NULL
, &msg
->pt
, &hittest
, FALSE
);
1513 TRACE("Got mouse message for %p, hittest: 0x%x\n", msg
->hwnd
, hittest
);
1515 // Null window or not the same "Hardware" message queue.
1516 if (pwndMsg
== NULL
|| pwndMsg
->head
.pti
->MessageQueue
!= MessageQueue
)
1518 // Crossing a boundary, so set cursor. See default message queue cursor.
1519 IntSystemSetCursor(SYSTEMCUR(ARROW
));
1520 /* Remove and ignore the message */
1521 *RemoveMessages
= TRUE
;
1525 // Check to see if this is attached,
1526 if ( pwndMsg
->head
.pti
!= pti
&& // window thread is not current,
1527 MessageQueue
->cThreads
> 1 ) // and is attached...
1529 // This is not for us and we should leave so the other thread can check for messages!!!
1531 *RemoveMessages
= TRUE
;
1535 if ( MessageQueue
== gpqCursor
) // Cursor must use the same Queue!
1537 IntTrackMouseMove(pwndMsg
, pDesk
, msg
, hittest
);
1541 ERR("Not the same cursor!\n");
1544 msg
->hwnd
= UserHMGetHandle(pwndMsg
);
1547 message
= msg
->message
;
1549 /* Note: windows has no concept of a non-client wheel message */
1550 if (message
!= WM_MOUSEWHEEL
)
1552 if (hittest
!= HTCLIENT
)
1554 message
+= WM_NCMOUSEMOVE
- WM_MOUSEMOVE
;
1555 msg
->wParam
= hittest
; // Caution! This might break wParam check in DblClk.
1559 /* coordinates don't get translated while tracking a menu */
1560 /* FIXME: should differentiate popups and top-level menus */
1561 if (!(MessageQueue
->MenuOwner
))
1563 pt
.x
+= pwndDesktop
->rcClient
.left
- pwndMsg
->rcClient
.left
;
1564 pt
.y
+= pwndDesktop
->rcClient
.top
- pwndMsg
->rcClient
.top
;
1568 msg
->lParam
= MAKELONG( pt
.x
, pt
.y
);
1570 /* translate double clicks */
1572 if ((msg
->message
== WM_LBUTTONDOWN
) ||
1573 (msg
->message
== WM_RBUTTONDOWN
) ||
1574 (msg
->message
== WM_MBUTTONDOWN
) ||
1575 (msg
->message
== WM_XBUTTONDOWN
))
1577 BOOL update
= *RemoveMessages
;
1579 /* translate double clicks -
1580 * note that ...MOUSEMOVEs can slip in between
1581 * ...BUTTONDOWN and ...BUTTONDBLCLK messages */
1583 if ((MessageQueue
->MenuOwner
|| MessageQueue
->MoveSize
) ||
1584 hittest
!= HTCLIENT
||
1585 (pwndMsg
->pcls
->style
& CS_DBLCLKS
))
1587 if ((msg
->message
== clk_msg
.message
) &&
1588 (msg
->hwnd
== clk_msg
.hwnd
) &&
1589 // Only worry about XButton wParam.
1590 (msg
->message
!= WM_XBUTTONDOWN
|| GET_XBUTTON_WPARAM(msg
->wParam
) == GET_XBUTTON_WPARAM(clk_msg
.wParam
)) &&
1591 ((msg
->time
- clk_msg
.time
) < (ULONG
)gspv
.iDblClickTime
) &&
1592 (abs(msg
->pt
.x
- clk_msg
.pt
.x
) < UserGetSystemMetrics(SM_CXDOUBLECLK
)/2) &&
1593 (abs(msg
->pt
.y
- clk_msg
.pt
.y
) < UserGetSystemMetrics(SM_CYDOUBLECLK
)/2))
1595 message
+= (WM_LBUTTONDBLCLK
- WM_LBUTTONDOWN
);
1598 MessageQueue
->msgDblClk
.message
= 0; /* clear the double click conditions */
1604 if (!((first
== 0 && last
== 0) || (message
>= first
|| message
<= last
)))
1606 TRACE("Message out of range!!!\n");
1610 /* update static double click conditions */
1611 if (update
) MessageQueue
->msgDblClk
= *msg
;
1615 if (!((first
== 0 && last
== 0) || (message
>= first
|| message
<= last
)))
1617 TRACE("Message out of range!!!\n");
1621 // Update mouse move down keys.
1622 if (message
== WM_MOUSEMOVE
)
1624 msg
->wParam
= MsqGetDownKeyState(MessageQueue
);
1628 if (gspv
.bMouseClickLock
)
1630 BOOL IsClkLck
= FALSE
;
1632 if(msg
->message
== WM_LBUTTONUP
)
1634 IsClkLck
= ((msg
->time
- CurInfo
->ClickLockTime
) >= gspv
.dwMouseClickLockTime
);
1635 if (IsClkLck
&& (!CurInfo
->ClickLockActive
))
1637 CurInfo
->ClickLockActive
= TRUE
;
1640 else if (msg
->message
== WM_LBUTTONDOWN
)
1642 if (CurInfo
->ClickLockActive
)
1645 CurInfo
->ClickLockActive
= FALSE
;
1648 CurInfo
->ClickLockTime
= msg
->time
;
1653 /* Remove and ignore the message */
1654 *RemoveMessages
= TRUE
;
1655 TRACE("Remove and ignore the message\n");
1660 if (pti
->TIF_flags
& TIF_MSGPOSCHANGED
)
1662 pti
->TIF_flags
&= ~TIF_MSGPOSCHANGED
;
1663 IntNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE
, NULL
, OBJID_CLIENT
, CHILDID_SELF
, 0);
1666 /* message is accepted now (but still get dropped) */
1668 event
.message
= msg
->message
;
1669 event
.time
= msg
->time
;
1670 event
.hwnd
= msg
->hwnd
;
1671 event
.paramL
= msg
->pt
.x
;
1672 event
.paramH
= msg
->pt
.y
;
1673 co_HOOK_CallHooks( WH_JOURNALRECORD
, HC_ACTION
, 0, (LPARAM
)&event
);
1676 hook
.hwnd
= msg
->hwnd
;
1677 hook
.wHitTestCode
= hittest
;
1678 hook
.dwExtraInfo
= ExtraInfo
;
1679 if (co_HOOK_CallHooks( WH_MOUSE
, *RemoveMessages
? HC_ACTION
: HC_NOREMOVE
,
1680 message
, (LPARAM
)&hook
))
1683 hook
.hwnd
= msg
->hwnd
;
1684 hook
.wHitTestCode
= hittest
;
1685 hook
.dwExtraInfo
= ExtraInfo
;
1686 co_HOOK_CallHooks( WH_CBT
, HCBT_CLICKSKIPPED
, message
, (LPARAM
)&hook
);
1688 ERR("WH_MOUSE dropped mouse message!\n");
1690 /* Remove and skip message */
1691 *RemoveMessages
= TRUE
;
1695 if ((hittest
== (USHORT
)HTERROR
) || (hittest
== (USHORT
)HTNOWHERE
))
1697 co_IntSendMessage( msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)msg
->hwnd
, MAKELONG( hittest
, msg
->message
));
1699 /* Remove and skip message */
1700 *RemoveMessages
= TRUE
;
1704 if ((*RemoveMessages
== FALSE
) || MessageQueue
->spwndCapture
)
1706 /* Accept the message */
1707 msg
->message
= message
;
1711 if ((msg
->message
== WM_LBUTTONDOWN
) ||
1712 (msg
->message
== WM_RBUTTONDOWN
) ||
1713 (msg
->message
== WM_MBUTTONDOWN
) ||
1714 (msg
->message
== WM_XBUTTONDOWN
))
1716 /* Send the WM_PARENTNOTIFY,
1717 * note that even for double/nonclient clicks
1718 * notification message is still WM_L/M/RBUTTONDOWN.
1720 MsqSendParentNotify(pwndMsg
, msg
->message
, 0, msg
->pt
);
1722 /* Activate the window if needed */
1724 if (pwndMsg
!= MessageQueue
->spwndActive
)
1726 PWND pwndTop
= pwndMsg
;
1727 pwndTop
= IntGetNonChildAncestor(pwndTop
);
1729 TRACE("Mouse pti %p pwndMsg pti %p pwndTop pti %p\n",MessageQueue
->ptiMouse
,pwndMsg
->head
.pti
,pwndTop
->head
.pti
);
1731 if (pwndTop
&& pwndTop
!= pwndDesktop
)
1733 LONG ret
= co_IntSendMessage( msg
->hwnd
,
1735 (WPARAM
)UserHMGetHandle(pwndTop
),
1736 MAKELONG( hittest
, msg
->message
));
1739 case MA_NOACTIVATEANDEAT
:
1744 case MA_ACTIVATEANDEAT
:
1749 if (!co_IntMouseActivateWindow( pwndTop
)) eatMsg
= TRUE
;
1752 ERR( "unknown WM_MOUSEACTIVATE code %d\n", ret
);
1759 /* send the WM_SETCURSOR message */
1761 /* Windows sends the normal mouse message as the message parameter
1762 in the WM_SETCURSOR message even if it's non-client mouse message */
1763 co_IntSendMessage( msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)msg
->hwnd
, MAKELONG( hittest
, msg
->message
));
1765 msg
->message
= message
;
1769 BOOL
co_IntProcessKeyboardMessage(MSG
* Msg
, BOOL
* RemoveMessages
)
1772 USER_REFERENCE_ENTRY Ref
;
1776 WPARAM wParam
= Msg
->wParam
;
1777 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
1779 if (Msg
->message
== VK_PACKET
)
1781 pti
->wchInjected
= HIWORD(Msg
->wParam
);
1784 if (Msg
->message
== WM_KEYDOWN
|| Msg
->message
== WM_SYSKEYDOWN
||
1785 Msg
->message
== WM_KEYUP
|| Msg
->message
== WM_SYSKEYUP
)
1787 switch (Msg
->wParam
)
1789 case VK_LSHIFT
: case VK_RSHIFT
:
1790 Msg
->wParam
= VK_SHIFT
;
1792 case VK_LCONTROL
: case VK_RCONTROL
:
1793 Msg
->wParam
= VK_CONTROL
;
1795 case VK_LMENU
: case VK_RMENU
:
1796 Msg
->wParam
= VK_MENU
;
1801 pWnd
= ValidateHwndNoErr(Msg
->hwnd
);
1802 if (pWnd
) UserRefObjectCo(pWnd
, &Ref
);
1804 Event
.message
= Msg
->message
;
1805 Event
.hwnd
= Msg
->hwnd
;
1806 Event
.time
= Msg
->time
;
1807 Event
.paramL
= (Msg
->wParam
& 0xFF) | (HIWORD(Msg
->lParam
) << 8);
1808 Event
.paramH
= Msg
->lParam
& 0x7FFF;
1809 if (HIWORD(Msg
->lParam
) & 0x0100) Event
.paramH
|= 0x8000;
1810 co_HOOK_CallHooks( WH_JOURNALRECORD
, HC_ACTION
, 0, (LPARAM
)&Event
);
1812 if (*RemoveMessages
)
1814 if ((Msg
->message
== WM_KEYDOWN
) &&
1815 (Msg
->hwnd
!= IntGetDesktopWindow()))
1817 /* Handle F1 key by sending out WM_HELP message */
1818 if (Msg
->wParam
== VK_F1
)
1820 UserPostMessage( Msg
->hwnd
, WM_KEYF1
, 0, 0 );
1822 else if (Msg
->wParam
>= VK_BROWSER_BACK
&&
1823 Msg
->wParam
<= VK_LAUNCH_APP2
)
1825 /* FIXME: Process keystate */
1826 co_IntSendMessage(Msg
->hwnd
, WM_APPCOMMAND
, (WPARAM
)Msg
->hwnd
, MAKELPARAM(0, (FAPPCOMMAND_KEY
| (Msg
->wParam
- VK_BROWSER_BACK
+ 1))));
1829 else if (Msg
->message
== WM_KEYUP
)
1831 /* Handle VK_APPS key by posting a WM_CONTEXTMENU message */
1832 if (Msg
->wParam
== VK_APPS
&& pti
->MessageQueue
->MenuOwner
== NULL
)
1833 UserPostMessage( Msg
->hwnd
, WM_CONTEXTMENU
, (WPARAM
)Msg
->hwnd
, -1 );
1838 if ( *RemoveMessages
&& Msg
->message
== WM_SYSKEYDOWN
)
1840 if ( HIWORD(Msg
->lParam
) & KF_ALTDOWN
)
1842 if ( Msg
->wParam
== VK_ESCAPE
|| Msg
->wParam
== VK_TAB
) // Alt-Tab/ESC Alt-Shift-Tab/ESC
1846 wParamTmp
= UserGetKeyState(VK_SHIFT
) & 0x8000 ? SC_PREVWINDOW
: SC_NEXTWINDOW
;
1847 TRACE("Send WM_SYSCOMMAND Alt-Tab/ESC Alt-Shift-Tab/ESC\n");
1848 co_IntSendMessage( Msg
->hwnd
, WM_SYSCOMMAND
, wParamTmp
, Msg
->wParam
);
1858 if ( *RemoveMessages
&& (Msg
->message
== WM_SYSKEYDOWN
|| Msg
->message
== WM_KEYDOWN
) )
1860 if (gdwLanguageToggleKey
< 3)
1862 if (IS_KEY_DOWN(gafAsyncKeyState
, gdwLanguageToggleKey
== 1 ? VK_LMENU
: VK_CONTROL
)) // L Alt 1 or Ctrl 2 .
1864 if ( wParam
== VK_LSHIFT
) gLanguageToggleKeyState
= INPUTLANGCHANGE_FORWARD
; // Left Alt - Left Shift, Next
1865 //// FIXME : It seems to always be VK_LSHIFT.
1866 if ( wParam
== VK_RSHIFT
) gLanguageToggleKeyState
= INPUTLANGCHANGE_BACKWARD
; // Left Alt - Right Shift, Previous
1871 //// Key Up! Alt Key Ctrl Key
1872 if ( *RemoveMessages
&& (Msg
->message
== WM_SYSKEYUP
|| Msg
->message
== WM_KEYUP
) )
1874 // When initializing win32k: Reading from the registry hotkey combination
1875 // to switch the keyboard layout and store it to global variable.
1876 // Using this combination of hotkeys in this function
1878 if ( gdwLanguageToggleKey
< 3 &&
1879 IS_KEY_DOWN(gafAsyncKeyState
, gdwLanguageToggleKey
== 1 ? VK_LMENU
: VK_CONTROL
) )
1881 if ( Msg
->wParam
== VK_SHIFT
&& !(IS_KEY_DOWN(gafAsyncKeyState
, VK_SHIFT
)))
1884 PKL pkl
= pti
->KeyboardLayout
;
1886 if (pWnd
) UserDerefObjectCo(pWnd
);
1888 //// Seems to override message window.
1889 if (!(pWnd
= pti
->MessageQueue
->spwndFocus
))
1891 pWnd
= pti
->MessageQueue
->spwndActive
;
1893 if (pWnd
) UserRefObjectCo(pWnd
, &Ref
);
1895 if (pkl
!= NULL
&& gLanguageToggleKeyState
)
1897 TRACE("Posting WM_INPUTLANGCHANGEREQUEST KeyState %d\n", gLanguageToggleKeyState
);
1899 wParamILR
= gLanguageToggleKeyState
;
1900 // If system character set and font signature send flag.
1901 if ( gSystemFS
& pkl
->dwFontSigs
)
1903 wParamILR
|= INPUTLANGCHANGE_SYSCHARSET
;
1906 UserPostMessage( UserHMGetHandle(pWnd
),
1907 WM_INPUTLANGCHANGEREQUEST
,
1911 gLanguageToggleKeyState
= 0;
1921 if (co_HOOK_CallHooks( WH_KEYBOARD
,
1922 *RemoveMessages
? HC_ACTION
: HC_NOREMOVE
,
1923 LOWORD(Msg
->wParam
),
1926 /* skip this message */
1927 co_HOOK_CallHooks( WH_CBT
,
1929 LOWORD(Msg
->wParam
),
1932 ERR("KeyboardMessage WH_KEYBOARD Call Hook return!\n");
1934 *RemoveMessages
= TRUE
;
1939 if ( pWnd
&& Ret
&& *RemoveMessages
&& Msg
->message
== WM_KEYDOWN
&& !(pti
->TIF_flags
& TIF_DISABLEIME
))
1941 if ( (ImmRet
= IntImmProcessKey(pti
->MessageQueue
, pWnd
, Msg
->message
, Msg
->wParam
, Msg
->lParam
)) )
1943 if ( ImmRet
& (IPHK_HOTKEY
|IPHK_SKIPTHISKEY
) )
1947 if ( ImmRet
& IPHK_PROCESSBYIME
)
1949 Msg
->wParam
= VK_PROCESSKEY
;
1954 if (pWnd
) UserDerefObjectCo(pWnd
);
1958 BOOL
co_IntProcessHardwareMessage(MSG
* Msg
, BOOL
* RemoveMessages
, BOOL
* NotForUs
, LONG_PTR ExtraInfo
, UINT first
, UINT last
)
1960 if ( IS_MOUSE_MESSAGE(Msg
->message
))
1962 return co_IntProcessMouseMessage(Msg
, RemoveMessages
, NotForUs
, ExtraInfo
, first
, last
);
1964 else if ( IS_KBD_MESSAGE(Msg
->message
))
1966 return co_IntProcessKeyboardMessage(Msg
, RemoveMessages
);
1972 /* check whether a message filter contains at least one potential hardware message */
1974 filter_contains_hw_range( UINT first
, UINT last
)
1976 /* hardware message ranges are (in numerical order):
1977 * WM_NCMOUSEFIRST .. WM_NCMOUSELAST
1978 * WM_KEYFIRST .. WM_KEYLAST
1979 * WM_MOUSEFIRST .. WM_MOUSELAST
1982 if (last
< WM_NCMOUSEFIRST
) return 0;
1983 if (first
> WM_NCMOUSELAST
&& last
< WM_KEYFIRST
) return 0;
1984 if (first
> WM_KEYLAST
&& last
< WM_MOUSEFIRST
) return 0;
1985 if (first
> WM_MOUSELAST
) return 0;
1989 /* check whether message is in the range of mouse messages */
1990 static inline BOOL
is_mouse_message( UINT message
)
1992 return ( //( message >= WM_NCMOUSEFIRST && message <= WM_NCMOUSELAST ) || This seems to break tests...
1993 ( message
>= WM_MOUSEFIRST
&& message
<= WM_MOUSELAST
) ||
1994 ( message
>= WM_XBUTTONDOWN
&& message
<= WM_XBUTTONDBLCLK
) ||
1995 ( message
>= WM_MBUTTONDOWN
&& message
<= WM_MBUTTONDBLCLK
) ||
1996 ( message
>= WM_LBUTTONDOWN
&& message
<= WM_RBUTTONDBLCLK
) );
2000 co_MsqPeekHardwareMessage(IN PTHREADINFO pti
,
2003 IN UINT MsgFilterLow
,
2004 IN UINT MsgFilterHigh
,
2008 BOOL AcceptMessage
, NotForUs
;
2009 PUSER_MESSAGE CurrentMessage
;
2010 PLIST_ENTRY ListHead
;
2016 PUSER_MESSAGE_QUEUE MessageQueue
= pti
->MessageQueue
;
2018 if (!filter_contains_hw_range( MsgFilterLow
, MsgFilterHigh
)) return FALSE
;
2020 ListHead
= MessageQueue
->HardwareMessagesListHead
.Flink
;
2022 if (IsListEmpty(ListHead
)) return FALSE
;
2024 if (!MessageQueue
->ptiSysLock
)
2026 MessageQueue
->ptiSysLock
= pti
;
2027 pti
->pcti
->CTI_flags
|= CTI_THREADSYSLOCK
;
2030 if (MessageQueue
->ptiSysLock
!= pti
)
2032 ERR("Thread Q is locked to ptiSysLock 0x%p pti 0x%p\n",MessageQueue
->ptiSysLock
,pti
);
2036 while (ListHead
!= &MessageQueue
->HardwareMessagesListHead
)
2038 CurrentMessage
= CONTAINING_RECORD(ListHead
, USER_MESSAGE
, ListEntry
);
2039 ListHead
= ListHead
->Flink
;
2041 if (MessageQueue
->idSysPeek
== (ULONG_PTR
)CurrentMessage
)
2043 TRACE("Skip this message due to it is in play!\n");
2048 1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL.
2049 2: retrieves only messages on the current thread's message queue whose hwnd value is NULL.
2050 3: handle to the window whose messages are to be retrieved.
2052 if ( ( !Window
|| // 1
2053 ( Window
== PWND_BOTTOM
&& CurrentMessage
->Msg
.hwnd
== NULL
) || // 2
2054 ( Window
!= PWND_BOTTOM
&& Window
->head
.h
== CurrentMessage
->Msg
.hwnd
) || // 3
2055 ( is_mouse_message(CurrentMessage
->Msg
.message
) ) ) && // Null window for anything mouse.
2056 ( ( ( MsgFilterLow
== 0 && MsgFilterHigh
== 0 ) && CurrentMessage
->QS_Flags
& QSflags
) ||
2057 ( MsgFilterLow
<= CurrentMessage
->Msg
.message
&& MsgFilterHigh
>= CurrentMessage
->Msg
.message
) ) )
2059 idSave
= MessageQueue
->idSysPeek
;
2060 MessageQueue
->idSysPeek
= (ULONG_PTR
)CurrentMessage
;
2062 msg
= CurrentMessage
->Msg
;
2063 ExtraInfo
= CurrentMessage
->ExtraInfo
;
2064 QS_Flags
= CurrentMessage
->QS_Flags
;
2068 UpdateKeyStateFromMsg(MessageQueue
, &msg
);
2069 AcceptMessage
= co_IntProcessHardwareMessage(&msg
, &Remove
, &NotForUs
, ExtraInfo
, MsgFilterLow
, MsgFilterHigh
);
2073 if (CurrentMessage
->pti
!= NULL
&& (MessageQueue
->idSysPeek
== (ULONG_PTR
)CurrentMessage
))
2075 MsqDestroyMessage(CurrentMessage
);
2077 ClearMsgBitsMask(pti
, QS_Flags
);
2080 MessageQueue
->idSysPeek
= idSave
;
2091 // Fix all but one wine win:test_GetMessagePos WM_TIMER tests. See PostTimerMessages.
2092 if (!RtlEqualMemory(&pti
->ptLast
, &msg
.pt
, sizeof(POINT
)))
2094 pti
->TIF_flags
|= TIF_MSGPOSCHANGED
;
2096 pti
->ptLast
= msg
.pt
;
2097 pti
->timeLast
= msg
.time
;
2098 MessageQueue
->ExtraInfo
= ExtraInfo
;
2105 MessageQueue
->ptiSysLock
= NULL
;
2106 pti
->pcti
->CTI_flags
&= ~CTI_THREADSYSLOCK
;
2111 MsqPeekMessage(IN PTHREADINFO pti
,
2114 IN UINT MsgFilterLow
,
2115 IN UINT MsgFilterHigh
,
2117 OUT LONG_PTR
*ExtraInfo
,
2118 OUT DWORD
*dwQEvent
,
2121 PUSER_MESSAGE CurrentMessage
;
2122 PLIST_ENTRY ListHead
;
2126 ListHead
= pti
->PostedMessagesListHead
.Flink
;
2128 if (IsListEmpty(ListHead
)) return FALSE
;
2130 while(ListHead
!= &pti
->PostedMessagesListHead
)
2132 CurrentMessage
= CONTAINING_RECORD(ListHead
, USER_MESSAGE
, ListEntry
);
2133 ListHead
= ListHead
->Flink
;
2136 1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL.
2137 2: retrieves only messages on the current thread's message queue whose hwnd value is NULL.
2138 3: handle to the window whose messages are to be retrieved.
2140 if ( ( !Window
|| // 1
2141 ( Window
== PWND_BOTTOM
&& CurrentMessage
->Msg
.hwnd
== NULL
) || // 2
2142 ( Window
!= PWND_BOTTOM
&& Window
->head
.h
== CurrentMessage
->Msg
.hwnd
) ) && // 3
2143 ( ( ( MsgFilterLow
== 0 && MsgFilterHigh
== 0 ) && CurrentMessage
->QS_Flags
& QSflags
) ||
2144 ( MsgFilterLow
<= CurrentMessage
->Msg
.message
&& MsgFilterHigh
>= CurrentMessage
->Msg
.message
) ) )
2146 *Message
= CurrentMessage
->Msg
;
2147 *ExtraInfo
= CurrentMessage
->ExtraInfo
;
2148 QS_Flags
= CurrentMessage
->QS_Flags
;
2149 if (dwQEvent
) *dwQEvent
= CurrentMessage
->dwQEvent
;
2153 if (CurrentMessage
->pti
!= NULL
)
2155 MsqDestroyMessage(CurrentMessage
);
2157 ClearMsgBitsMask(pti
, QS_Flags
);
2168 co_MsqWaitForNewMessages(PTHREADINFO pti
, PWND WndFilter
,
2169 UINT MsgFilterMin
, UINT MsgFilterMax
)
2171 NTSTATUS ret
= STATUS_SUCCESS
;
2173 // Post mouse moves before waiting for messages.
2174 if (pti
->MessageQueue
->QF_flags
& QF_MOUSEMOVED
)
2176 IntCoalesceMouseMove(pti
);
2181 ZwYieldExecution(); // Let someone else run!
2183 ret
= KeWaitForSingleObject( pti
->pEventQueueServer
,
2189 if ( ret
== STATUS_USER_APC
)
2191 TRACE("MWFNW User APC\n");
2192 co_IntDeliverUserAPC();
2198 MsqIsHung(PTHREADINFO pti
)
2200 LARGE_INTEGER LargeTickCount
;
2202 KeQueryTickCount(&LargeTickCount
);
2204 if ((LargeTickCount
.u
.LowPart
- pti
->timeLast
) > MSQ_HUNG
&&
2205 !(pti
->pcti
->fsWakeMask
& QS_INPUT
) &&
2206 !PsGetThreadFreezeCount(pti
->pEThread
) &&
2207 !(pti
->ppi
->W32PF_flags
& W32PF_APPSTARTING
))
2214 IsThreadSuspended(PTHREADINFO pti
)
2219 ObReferenceObject(pti
->pEThread
);
2220 if (!(pti
->pEThread
->Tcb
.SuspendCount
) && !PsGetThreadFreezeCount(pti
->pEThread
)) Ret
= FALSE
;
2221 ObDereferenceObject(pti
->pEThread
);
2229 HungAppSysTimerProc(HWND hwnd
, UINT uMsg
, UINT_PTR idEvent
, DWORD dwTime
)
2232 TRACE("HungAppSysTimerProc\n");
2233 // Process list of windows that are hung and waiting.
2237 MsqInitializeMessageQueue(PTHREADINFO pti
, PUSER_MESSAGE_QUEUE MessageQueue
)
2239 InitializeListHead(&MessageQueue
->HardwareMessagesListHead
); // Keep here!
2240 MessageQueue
->spwndFocus
= NULL
;
2241 MessageQueue
->iCursorLevel
= 0;
2242 MessageQueue
->CursorObject
= SYSTEMCUR(WAIT
); // See test_initial_cursor.
2243 if (MessageQueue
->CursorObject
)
2245 TRACE("Default cursor hcur %p\n",UserHMGetHandle(MessageQueue
->CursorObject
));
2246 UserReferenceObject(MessageQueue
->CursorObject
);
2248 RtlCopyMemory(MessageQueue
->afKeyState
, gafAsyncKeyState
, sizeof(gafAsyncKeyState
));
2249 MessageQueue
->ptiMouse
= pti
;
2250 MessageQueue
->ptiKeyboard
= pti
;
2251 MessageQueue
->cThreads
++;
2257 MsqCleanupThreadMsgs(PTHREADINFO pti
)
2259 PLIST_ENTRY CurrentEntry
;
2260 PUSER_MESSAGE CurrentMessage
;
2261 PUSER_SENT_MESSAGE CurrentSentMessage
;
2263 TRACE("MsqCleanupThreadMsgs %p\n",pti
);
2265 // Clear it all out.
2268 pti
->pcti
->fsWakeBits
= 0;
2269 pti
->pcti
->fsChangeBits
= 0;
2272 pti
->nCntsQBits
[QSRosKey
] = 0;
2273 pti
->nCntsQBits
[QSRosMouseMove
] = 0;
2274 pti
->nCntsQBits
[QSRosMouseButton
] = 0;
2275 pti
->nCntsQBits
[QSRosPostMessage
] = 0;
2276 pti
->nCntsQBits
[QSRosSendMessage
] = 0;
2277 pti
->nCntsQBits
[QSRosHotKey
] = 0;
2278 pti
->nCntsQBits
[QSRosEvent
] = 0;
2280 /* cleanup posted messages */
2281 while (!IsListEmpty(&pti
->PostedMessagesListHead
))
2283 CurrentEntry
= pti
->PostedMessagesListHead
.Flink
;
2284 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
, ListEntry
);
2285 ERR("Thread Cleanup Post Messages %p\n",CurrentMessage
);
2286 if (CurrentMessage
->dwQEvent
)
2288 if (CurrentMessage
->dwQEvent
== POSTEVENT_NWE
)
2290 ExFreePoolWithTag( (PVOID
)CurrentMessage
->ExtraInfo
, TAG_HOOK
);
2293 MsqDestroyMessage(CurrentMessage
);
2296 /* remove the messages that have not yet been dispatched */
2297 while (!IsListEmpty(&pti
->SentMessagesListHead
))
2299 CurrentEntry
= pti
->SentMessagesListHead
.Flink
;
2300 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
, ListEntry
);
2302 ERR("Thread Cleanup Sent Messages %p\n",CurrentSentMessage
);
2304 /* wake the sender's thread */
2305 if (CurrentSentMessage
->pkCompletionEvent
!= NULL
)
2307 KeSetEvent(CurrentSentMessage
->pkCompletionEvent
, IO_NO_INCREMENT
, FALSE
);
2310 if (CurrentSentMessage
->HasPackedLParam
)
2312 if (CurrentSentMessage
->Msg
.lParam
)
2313 ExFreePool((PVOID
)CurrentSentMessage
->Msg
.lParam
);
2316 /* free the message */
2317 FreeUserMessage(CurrentSentMessage
);
2320 // Process Trouble Message List
2321 if (!IsListEmpty(&usmList
))
2323 CurrentEntry
= usmList
.Flink
;
2324 while (CurrentEntry
!= &usmList
)
2326 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
, ListEntry
);
2327 CurrentEntry
= CurrentEntry
->Flink
;
2329 TRACE("Found troubled messages %p on the list\n",CurrentSentMessage
);
2331 if ( pti
== CurrentSentMessage
->ptiReceiver
)
2333 if (CurrentSentMessage
->HasPackedLParam
)
2335 if (CurrentSentMessage
->Msg
.lParam
)
2336 ExFreePool((PVOID
)CurrentSentMessage
->Msg
.lParam
);
2339 /* free the message */
2340 FreeUserMessage(CurrentSentMessage
);
2342 else if ( pti
== CurrentSentMessage
->ptiSender
||
2343 pti
== CurrentSentMessage
->ptiCallBackSender
)
2345 // Determine whether this message is being processed or not.
2346 if ((CurrentSentMessage
->flags
& (SMF_RECEIVERBUSY
|SMF_RECEIVEDMESSAGE
)) != SMF_RECEIVEDMESSAGE
)
2348 CurrentSentMessage
->flags
|= SMF_RECEIVERFREE
;
2351 if (!(CurrentSentMessage
->flags
& SMF_RECEIVERFREE
))
2354 if (CurrentSentMessage
->HasPackedLParam
)
2356 if (CurrentSentMessage
->Msg
.lParam
)
2357 ExFreePool((PVOID
)CurrentSentMessage
->Msg
.lParam
);
2360 /* free the message */
2361 FreeUserMessage(CurrentSentMessage
);
2369 MsqCleanupMessageQueue(PTHREADINFO pti
)
2371 PUSER_MESSAGE_QUEUE MessageQueue
;
2372 PLIST_ENTRY CurrentEntry
;
2373 PUSER_MESSAGE CurrentMessage
;
2375 MessageQueue
= pti
->MessageQueue
;
2376 MessageQueue
->cThreads
--;
2378 if (MessageQueue
->cThreads
)
2380 if (MessageQueue
->ptiSysLock
== pti
) MessageQueue
->ptiSysLock
= NULL
;
2383 if (MessageQueue
->cThreads
== 0) //// Fix a crash related to CORE-10471 testing.
2385 /* cleanup posted messages */
2386 while (!IsListEmpty(&MessageQueue
->HardwareMessagesListHead
))
2388 CurrentEntry
= MessageQueue
->HardwareMessagesListHead
.Flink
;
2389 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
, ListEntry
);
2390 ERR("MQ Cleanup Post Messages %p\n",CurrentMessage
);
2391 MsqDestroyMessage(CurrentMessage
);
2395 if (MessageQueue
->CursorObject
)
2397 PCURICON_OBJECT pCursor
= MessageQueue
->CursorObject
;
2399 /* Change to another cursor if we going to dereference current one
2400 Note: we can't use UserSetCursor because it uses current thread
2401 message queue instead of queue given for cleanup */
2402 if (IntGetSysCursorInfo()->CurrentCursorObject
== pCursor
)
2406 /* Get the screen DC */
2407 hdcScreen
= IntGetScreenDC();
2409 GreMovePointer(hdcScreen
, -1, -1);
2410 IntGetSysCursorInfo()->CurrentCursorObject
= NULL
;
2413 TRACE("DereferenceObject pCursor\n");
2414 UserDereferenceObject(pCursor
);
2417 if (gpqForeground
== MessageQueue
)
2419 IntSetFocusMessageQueue(NULL
);
2421 if (gpqForegroundPrev
== MessageQueue
)
2423 gpqForegroundPrev
= NULL
;
2425 if (gpqCursor
== MessageQueue
)
2431 PUSER_MESSAGE_QUEUE FASTCALL
2432 MsqCreateMessageQueue(PTHREADINFO pti
)
2434 PUSER_MESSAGE_QUEUE MessageQueue
;
2436 MessageQueue
= ExAllocatePoolWithTag(NonPagedPool
,
2437 sizeof(*MessageQueue
),
2445 RtlZeroMemory(MessageQueue
, sizeof(*MessageQueue
));
2446 /* hold at least one reference until it'll be destroyed */
2447 IntReferenceMessageQueue(MessageQueue
);
2448 /* initialize the queue */
2449 if (!MsqInitializeMessageQueue(pti
, MessageQueue
))
2451 IntDereferenceMessageQueue(MessageQueue
);
2455 return MessageQueue
;
2459 MsqDestroyMessageQueue(_In_ PTHREADINFO pti
)
2462 PUSER_MESSAGE_QUEUE MessageQueue
= pti
->MessageQueue
;
2464 NT_ASSERT(MessageQueue
!= NULL
);
2465 MessageQueue
->QF_flags
|= QF_INDESTROY
;
2467 /* remove the message queue from any desktops */
2468 if ((desk
= InterlockedExchangePointer((PVOID
*)&MessageQueue
->Desktop
, 0)))
2470 (void)InterlockedExchangePointer((PVOID
*)&desk
->ActiveMessageQueue
, 0);
2471 IntDereferenceMessageQueue(MessageQueue
);
2475 MsqCleanupMessageQueue(pti
);
2477 /* decrease the reference counter, if it hits zero, the queue will be freed */
2478 _PRAGMA_WARNING_SUPPRESS(__WARNING_USING_UNINIT_VAR
);
2479 IntDereferenceMessageQueue(MessageQueue
);
2483 MsqSetMessageExtraInfo(LPARAM lParam
)
2487 PUSER_MESSAGE_QUEUE MessageQueue
;
2489 pti
= PsGetCurrentThreadWin32Thread();
2490 MessageQueue
= pti
->MessageQueue
;
2496 Ret
= MessageQueue
->ExtraInfo
;
2497 MessageQueue
->ExtraInfo
= lParam
;
2503 MsqGetMessageExtraInfo(VOID
)
2506 PUSER_MESSAGE_QUEUE MessageQueue
;
2508 pti
= PsGetCurrentThreadWin32Thread();
2509 MessageQueue
= pti
->MessageQueue
;
2515 return MessageQueue
->ExtraInfo
;
2518 // ReplyMessage is called by the thread receiving the window message.
2520 co_MsqReplyMessage( LRESULT lResult
)
2522 PUSER_SENT_MESSAGE Message
;
2525 pti
= PsGetCurrentThreadWin32Thread();
2526 Message
= pti
->pusmCurrent
;
2528 if (!Message
) return FALSE
;
2530 if (Message
->QS_Flags
& QS_SMRESULT
) return FALSE
;
2532 // SendMessageXxx || Callback msg and not a notify msg
2533 if (Message
->ptiSender
|| Message
->CompletionCallback
)
2535 Message
->lResult
= lResult
;
2536 Message
->QS_Flags
|= QS_SMRESULT
;
2537 // See co_MsqDispatchOneSentMessage, change bits already accounted for and cleared and this msg is going away..
2543 MsqSetStateWindow(PTHREADINFO pti
, ULONG Type
, HWND hWnd
)
2546 PUSER_MESSAGE_QUEUE MessageQueue
;
2548 MessageQueue
= pti
->MessageQueue
;
2552 case MSQ_STATE_CAPTURE
:
2553 Prev
= MessageQueue
->spwndCapture
? UserHMGetHandle(MessageQueue
->spwndCapture
) : 0;
2554 MessageQueue
->spwndCapture
= ValidateHwndNoErr(hWnd
);
2556 case MSQ_STATE_ACTIVE
:
2557 Prev
= MessageQueue
->spwndActive
? UserHMGetHandle(MessageQueue
->spwndActive
) : 0;
2558 MessageQueue
->spwndActive
= ValidateHwndNoErr(hWnd
);
2560 case MSQ_STATE_FOCUS
:
2561 Prev
= MessageQueue
->spwndFocus
? UserHMGetHandle(MessageQueue
->spwndFocus
) : 0;
2562 MessageQueue
->spwndFocus
= ValidateHwndNoErr(hWnd
);
2564 case MSQ_STATE_MENUOWNER
:
2565 Prev
= MessageQueue
->MenuOwner
;
2566 MessageQueue
->MenuOwner
= hWnd
;
2568 case MSQ_STATE_MOVESIZE
:
2569 Prev
= MessageQueue
->MoveSize
;
2570 MessageQueue
->MoveSize
= hWnd
;
2572 case MSQ_STATE_CARET
:
2573 Prev
= MessageQueue
->CaretInfo
.hWnd
;
2574 MessageQueue
->CaretInfo
.hWnd
= hWnd
;
2583 NtUserGetKeyState(INT key
)
2589 Ret
= UserGetKeyState(key
);
2599 NtUserGetKeyboardState(LPBYTE lpKeyState
)
2601 DWORD i
, ret
= TRUE
;
2603 PUSER_MESSAGE_QUEUE MessageQueue
;
2607 pti
= PsGetCurrentThreadWin32Thread();
2608 MessageQueue
= pti
->MessageQueue
;
2612 /* Probe and copy key state to an array */
2613 ProbeForWrite(lpKeyState
, 256 * sizeof(BYTE
), 1);
2614 for (i
= 0; i
< 256; ++i
)
2617 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, i
))
2618 lpKeyState
[i
] |= KS_DOWN_BIT
;
2619 if (IS_KEY_LOCKED(MessageQueue
->afKeyState
, i
))
2620 lpKeyState
[i
] |= KS_LOCK_BIT
;
2623 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2625 SetLastNtError(_SEH2_GetExceptionCode());
2637 NtUserSetKeyboardState(LPBYTE pKeyState
)
2642 PUSER_MESSAGE_QUEUE MessageQueue
;
2644 UserEnterExclusive();
2646 pti
= PsGetCurrentThreadWin32Thread();
2647 MessageQueue
= pti
->MessageQueue
;
2651 ProbeForRead(pKeyState
, 256 * sizeof(BYTE
), 1);
2652 for (i
= 0; i
< 256; ++i
)
2654 SET_KEY_DOWN(MessageQueue
->afKeyState
, i
, pKeyState
[i
] & KS_DOWN_BIT
);
2655 SET_KEY_LOCKED(MessageQueue
->afKeyState
, i
, pKeyState
[i
] & KS_LOCK_BIT
);
2658 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2660 SetLastNtError(_SEH2_GetExceptionCode());