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 PUSER_MESSAGE_QUEUE gpqCursor
;
18 ULONG_PTR gdwMouseMoveExtraInfo
= 0;
19 DWORD gdwMouseMoveTimeStamp
= 0;
22 /* FUNCTIONS *****************************************************************/
27 MsqInitializeImpl(VOID
)
29 pgMessageLookasideList
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(PAGED_LOOKASIDE_LIST
), TAG_USRMSG
);
30 if (!pgMessageLookasideList
)
31 return STATUS_NO_MEMORY
;
32 ExInitializePagedLookasideList(pgMessageLookasideList
,
40 return(STATUS_SUCCESS
);
44 IntTopLevelWindowFromPoint(INT x
, INT y
)
46 PWND pWnd
, pwndDesktop
;
48 /* Get the desktop window */
49 pwndDesktop
= UserGetDesktopWindow();
53 /* Loop all top level windows */
54 for (pWnd
= pwndDesktop
->spwndChild
;
56 pWnd
= pWnd
->spwndNext
)
58 if (pWnd
->state2
& WNDS2_INDESTROY
|| pWnd
->state
& WNDS_DESTROYED
)
60 TRACE("The Window is in DESTROY!\n");
64 if ((pWnd
->style
& WS_VISIBLE
) && IntPtInWindow(pWnd
, x
, y
))
68 /* Window has not been found */
75 PCURICON_OBJECT NewCursor
,
78 PCURICON_OBJECT OldCursor
;
81 PUSER_MESSAGE_QUEUE MessageQueue
;
84 pti
= PsGetCurrentThreadWin32Thread();
85 MessageQueue
= pti
->MessageQueue
;
87 /* Get the screen DC */
88 if(!(hdcScreen
= IntGetScreenDC()))
93 OldCursor
= MessageQueue
->CursorObject
;
95 /* Check if cursors are different */
96 if (OldCursor
== NewCursor
)
99 /* Update cursor for this message queue */
100 MessageQueue
->CursorObject
= NewCursor
;
102 /* If cursor is not visible we have nothing to do */
103 if (MessageQueue
->iCursorLevel
< 0)
106 /* Update cursor if this message queue controls it */
107 pWnd
= IntTopLevelWindowFromPoint(gpsi
->ptCursor
.x
, gpsi
->ptCursor
.y
);
108 if (pWnd
&& pWnd
->head
.pti
->MessageQueue
== MessageQueue
)
112 /* Call GDI to set the new screen cursor */
113 #ifdef NEW_CURSORICON
114 PCURICON_OBJECT CursorFrame
= NewCursor
;
115 if(NewCursor
->CURSORF_flags
& CURSORF_ACON
)
117 FIXME("Should animate the cursor, using only the first frame now.\n");
118 CursorFrame
= ((PACON
)NewCursor
)->aspcur
[0];
120 GreSetPointerShape(hdcScreen
,
121 CursorFrame
->hbmAlpha
? NULL
: NewCursor
->hbmMask
,
122 CursorFrame
->hbmAlpha
? NewCursor
->hbmAlpha
: NewCursor
->hbmColor
,
123 CursorFrame
->xHotspot
,
124 CursorFrame
->yHotspot
,
127 CursorFrame
->hbmAlpha
? SPS_ALPHA
: 0);
129 GreSetPointerShape(hdcScreen
,
130 NewCursor
->IconInfo
.hbmMask
,
131 NewCursor
->IconInfo
.hbmColor
,
132 NewCursor
->IconInfo
.xHotspot
,
133 NewCursor
->IconInfo
.yHotspot
,
139 else /* Note: OldCursor != NewCursor so we have to hide cursor */
141 /* Remove the cursor */
142 GreMovePointer(hdcScreen
, -1, -1);
143 TRACE("Removing pointer!\n");
145 IntGetSysCursorInfo()->CurrentCursorObject
= NewCursor
;
148 /* Return the old cursor */
152 /* Called from NtUserCallOneParam with Routine ONEPARAM_ROUTINE_SHOWCURSOR
153 * User32 macro NtUserShowCursor */
154 int UserShowCursor(BOOL bShow
)
158 PUSER_MESSAGE_QUEUE MessageQueue
;
161 if (!(hdcScreen
= IntGetScreenDC()))
163 return -1; /* No mouse */
166 pti
= PsGetCurrentThreadWin32Thread();
167 MessageQueue
= pti
->MessageQueue
;
170 MessageQueue
->iCursorLevel
+= bShow
? 1 : -1;
171 pti
->iCursorLevel
+= bShow
? 1 : -1;
173 /* Check for trivial cases */
174 if ((bShow
&& MessageQueue
->iCursorLevel
!= 0) ||
175 (!bShow
&& MessageQueue
->iCursorLevel
!= -1))
177 /* Note: w don't update global info here because it is used only
178 internally to check if cursor is visible */
179 return MessageQueue
->iCursorLevel
;
182 /* Check if cursor is above window owned by this MessageQueue */
183 pWnd
= IntTopLevelWindowFromPoint(gpsi
->ptCursor
.x
, gpsi
->ptCursor
.y
);
184 if (pWnd
&& pWnd
->head
.pti
->MessageQueue
== MessageQueue
)
188 /* Show the pointer */
189 GreMovePointer(hdcScreen
, gpsi
->ptCursor
.x
, gpsi
->ptCursor
.y
);
190 TRACE("Showing pointer!\n");
194 /* Remove the pointer */
195 GreMovePointer(hdcScreen
, -1, -1);
196 TRACE("Removing pointer!\n");
199 /* Update global info */
200 IntGetSysCursorInfo()->ShowingCursor
= MessageQueue
->iCursorLevel
;
203 return MessageQueue
->iCursorLevel
;
207 UserGetKeyState(DWORD dwKey
)
211 PUSER_MESSAGE_QUEUE MessageQueue
;
213 pti
= PsGetCurrentThreadWin32Thread();
214 MessageQueue
= pti
->MessageQueue
;
218 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, dwKey
))
219 dwRet
|= 0xFF80; // If down, windows returns 0xFF80.
220 if (IS_KEY_LOCKED(MessageQueue
->afKeyState
, dwKey
))
225 EngSetLastError(ERROR_INVALID_PARAMETER
);
230 /* change the input key state for a given key */
232 UpdateKeyState(PUSER_MESSAGE_QUEUE MessageQueue
, WORD wVk
, BOOL bIsDown
)
234 TRACE("UpdateKeyState wVk: %u, bIsDown: %d\n", wVk
, bIsDown
);
238 /* If it's first key down event, xor lock bit */
239 if (!IS_KEY_DOWN(MessageQueue
->afKeyState
, wVk
))
240 SET_KEY_LOCKED(MessageQueue
->afKeyState
, wVk
, !IS_KEY_LOCKED(MessageQueue
->afKeyState
, wVk
));
242 SET_KEY_DOWN(MessageQueue
->afKeyState
, wVk
, TRUE
);
243 MessageQueue
->afKeyRecentDown
[wVk
/ 8] |= (1 << (wVk
% 8));
246 SET_KEY_DOWN(MessageQueue
->afKeyState
, wVk
, FALSE
);
249 /* update the input key state for a keyboard message */
251 UpdateKeyStateFromMsg(PUSER_MESSAGE_QUEUE MessageQueue
, MSG
* msg
)
256 TRACE("UpdateKeyStateFromMsg message:%u\n", msg
->message
);
258 switch (msg
->message
)
264 UpdateKeyState(MessageQueue
, VK_LBUTTON
, down
);
270 UpdateKeyState(MessageQueue
, VK_MBUTTON
, down
);
276 UpdateKeyState(MessageQueue
, VK_RBUTTON
, down
);
282 if (msg
->wParam
== XBUTTON1
)
283 UpdateKeyState(MessageQueue
, VK_XBUTTON1
, down
);
284 else if (msg
->wParam
== XBUTTON2
)
285 UpdateKeyState(MessageQueue
, VK_XBUTTON2
, down
);
293 key
= (UCHAR
)msg
->wParam
;
294 UpdateKeyState(MessageQueue
, key
, down
);
299 down
= IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_LCONTROL
) || IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_RCONTROL
);
300 UpdateKeyState(MessageQueue
, VK_CONTROL
, down
);
304 down
= IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_LMENU
) || IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_RMENU
);
305 UpdateKeyState(MessageQueue
, VK_MENU
, down
);
309 down
= IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_LSHIFT
) || IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_RSHIFT
);
310 UpdateKeyState(MessageQueue
, VK_SHIFT
, down
);
318 Get down key states from the queue of prior processed input message key states.
320 This fixes the left button dragging on the desktop and release sticking outline issue.
321 USB Tablet pointer seems to stick the most and leaves the box outline displayed.
324 MsqGetDownKeyState(PUSER_MESSAGE_QUEUE MessageQueue
)
328 if (gspv
.bMouseBtnSwap
)
330 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_RBUTTON
)) ret
|= MK_LBUTTON
;
331 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_LBUTTON
)) ret
|= MK_RBUTTON
;
335 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_LBUTTON
)) ret
|= MK_LBUTTON
;
336 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_RBUTTON
)) ret
|= MK_RBUTTON
;
339 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_MBUTTON
)) ret
|= MK_MBUTTON
;
340 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_SHIFT
)) ret
|= MK_SHIFT
;
341 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_CONTROL
)) ret
|= MK_CONTROL
;
342 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_XBUTTON1
)) ret
|= MK_XBUTTON1
;
343 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, VK_XBUTTON2
)) ret
|= MK_XBUTTON2
;
348 IntMsqSetWakeMask(DWORD WakeMask
)
350 PTHREADINFO Win32Thread
;
351 HANDLE MessageEventHandle
;
352 DWORD dwFlags
= HIWORD(WakeMask
);
354 Win32Thread
= PsGetCurrentThreadWin32Thread();
355 if (Win32Thread
== NULL
|| Win32Thread
->MessageQueue
== NULL
)
358 // Win32Thread->pEventQueueServer; IntMsqSetWakeMask returns Win32Thread->hEventQueueClient
359 MessageEventHandle
= Win32Thread
->hEventQueueClient
;
361 if (Win32Thread
->pcti
)
363 if ( (Win32Thread
->pcti
->fsChangeBits
& LOWORD(WakeMask
)) ||
364 ( (dwFlags
& MWMO_INPUTAVAILABLE
) && (Win32Thread
->pcti
->fsWakeBits
& LOWORD(WakeMask
)) ) )
366 ERR("Chg 0x%x Wake 0x%x Mask 0x%x\n",Win32Thread
->pcti
->fsChangeBits
, Win32Thread
->pcti
->fsWakeBits
, WakeMask
);
367 KeSetEvent(Win32Thread
->pEventQueueServer
, IO_NO_INCREMENT
, FALSE
); // Wake it up!
368 return MessageEventHandle
;
374 return MessageEventHandle
;
378 IntMsqClearWakeMask(VOID
)
380 PTHREADINFO Win32Thread
;
382 Win32Thread
= PsGetCurrentThreadWin32Thread();
383 if (Win32Thread
== NULL
|| Win32Thread
->MessageQueue
== NULL
)
385 // Very hacky, but that is what they do.
386 Win32Thread
->pcti
->fsWakeBits
= 0;
394 Due to the uncertainty of knowing what was set in our multilevel message queue,
395 and even if the bits are all cleared. The same as cTimers/cPaintsReady.
396 I think this is the best solution... (jt) */
398 MsqWakeQueue(PTHREADINFO pti
, DWORD MessageBits
, BOOL KeyEvent
)
400 PUSER_MESSAGE_QUEUE Queue
;
402 Queue
= pti
->MessageQueue
;
404 if (Queue
->QF_flags
& QF_INDESTROY
)
406 ERR("This Message Queue is in Destroy!\n");
408 pti
->pcti
->fsWakeBits
|= MessageBits
;
409 pti
->pcti
->fsChangeBits
|= MessageBits
;
411 // Start bit accounting to help clear the main set of bits.
412 if (MessageBits
& QS_KEY
)
414 pti
->nCntsQBits
[QSRosKey
]++;
416 if (MessageBits
& QS_MOUSE
)
418 if (MessageBits
& QS_MOUSEMOVE
) pti
->nCntsQBits
[QSRosMouseMove
]++;
419 if (MessageBits
& QS_MOUSEBUTTON
) pti
->nCntsQBits
[QSRosMouseButton
]++;
421 if (MessageBits
& QS_POSTMESSAGE
) pti
->nCntsQBits
[QSRosPostMessage
]++;
422 if (MessageBits
& QS_SENDMESSAGE
) pti
->nCntsQBits
[QSRosSendMessage
]++;
423 if (MessageBits
& QS_HOTKEY
) pti
->nCntsQBits
[QSRosHotKey
]++;
424 if (MessageBits
& QS_EVENT
) pti
->nCntsQBits
[QSRosEvent
]++;
427 KeSetEvent(pti
->pEventQueueServer
, IO_NO_INCREMENT
, FALSE
);
431 ClearMsgBitsMask(PTHREADINFO pti
, UINT MessageBits
)
435 if (MessageBits
& QS_KEY
)
437 if (--pti
->nCntsQBits
[QSRosKey
] == 0) ClrMask
|= QS_KEY
;
439 if (MessageBits
& QS_MOUSEMOVE
)
440 { // Account for tracking mouse moves..
441 if (pti
->nCntsQBits
[QSRosMouseMove
])
443 pti
->nCntsQBits
[QSRosMouseMove
] = 0; // Throttle down count. Up to > 3:1 entries are ignored.
444 ClrMask
|= QS_MOUSEMOVE
;
447 if (MessageBits
& QS_MOUSEBUTTON
)
449 if (--pti
->nCntsQBits
[QSRosMouseButton
] == 0) ClrMask
|= QS_MOUSEBUTTON
;
451 if (MessageBits
& QS_POSTMESSAGE
)
453 if (--pti
->nCntsQBits
[QSRosPostMessage
] == 0) ClrMask
|= QS_POSTMESSAGE
;
455 if (MessageBits
& QS_TIMER
) // ReactOS hard coded.
456 { // Handle timer bits here.
457 if ( pti
->cTimersReady
)
459 if (--pti
->cTimersReady
== 0) ClrMask
|= QS_TIMER
;
462 if (MessageBits
& QS_PAINT
) // ReactOS hard coded.
463 { // Handle paint bits here.
464 if ( pti
->cPaintsReady
)
466 if (--pti
->cPaintsReady
== 0) ClrMask
|= QS_PAINT
;
469 if (MessageBits
& QS_SENDMESSAGE
)
471 if (--pti
->nCntsQBits
[QSRosSendMessage
] == 0) ClrMask
|= QS_SENDMESSAGE
;
473 if (MessageBits
& QS_HOTKEY
)
475 if (--pti
->nCntsQBits
[QSRosHotKey
] == 0) ClrMask
|= QS_HOTKEY
;
477 if (MessageBits
& QS_EVENT
)
479 if (--pti
->nCntsQBits
[QSRosEvent
] == 0) ClrMask
|= QS_EVENT
;
482 pti
->pcti
->fsWakeBits
&= ~ClrMask
;
483 pti
->pcti
->fsChangeBits
&= ~ClrMask
;
487 MsqIncPaintCountQueue(PTHREADINFO pti
)
490 MsqWakeQueue(pti
, QS_PAINT
, TRUE
);
494 MsqDecPaintCountQueue(PTHREADINFO pti
)
496 ClearMsgBitsMask(pti
, QS_PAINT
);
500 Post the move or update the message still pending to be processed.
501 Do not overload the queue with mouse move messages.
504 MsqPostMouseMove(PTHREADINFO pti
, MSG
* Msg
, LONG_PTR ExtraInfo
)
506 PUSER_MESSAGE Message
;
507 PLIST_ENTRY ListHead
;
508 PUSER_MESSAGE_QUEUE MessageQueue
= pti
->MessageQueue
;
510 ListHead
= &MessageQueue
->HardwareMessagesListHead
;
512 // Do nothing if empty.
513 if (!IsListEmpty(ListHead
->Flink
))
515 // Look at the end of the list,
516 Message
= CONTAINING_RECORD(ListHead
->Blink
, USER_MESSAGE
, ListEntry
);
518 // If the mouse move message is existing on the list,
519 if (Message
->Msg
.message
== WM_MOUSEMOVE
)
521 // Overwrite the message with updated data!
524 MsqWakeQueue(pti
, QS_MOUSEMOVE
, TRUE
);
529 MsqPostMessage(pti
, Msg
, TRUE
, QS_MOUSEMOVE
, 0, ExtraInfo
);
533 Bring together the mouse move message.
534 Named "Coalesce" from Amine email ;^) (jt).
537 IntCoalesceMouseMove(PTHREADINFO pti
)
540 LARGE_INTEGER LargeTickCount
;
542 // Force time stamp to update, keeping message time in sync.
543 if (gdwMouseMoveTimeStamp
== 0)
545 KeQueryTickCount(&LargeTickCount
);
546 gdwMouseMoveTimeStamp
= MsqCalculateMessageTime(&LargeTickCount
);
549 // Build mouse move message.
551 Msg
.message
= WM_MOUSEMOVE
;
553 Msg
.lParam
= MAKELONG(gpsi
->ptCursor
.x
, gpsi
->ptCursor
.y
);
554 Msg
.time
= gdwMouseMoveTimeStamp
;
555 Msg
.pt
= gpsi
->ptCursor
;
558 MsqPostMouseMove(pti
, &Msg
, gdwMouseMoveExtraInfo
);
560 // Zero the time stamp.
561 gdwMouseMoveTimeStamp
= 0;
563 // Clear flag since the move was posted.
564 pti
->MessageQueue
->QF_flags
&= ~QF_MOUSEMOVED
;
568 co_MsqInsertMouseMessage(MSG
* Msg
, DWORD flags
, ULONG_PTR dwExtraInfo
, BOOL Hook
)
570 LARGE_INTEGER LargeTickCount
;
571 MSLLHOOKSTRUCT MouseHookData
;
573 PWND pwnd
, pwndDesktop
;
576 PUSER_MESSAGE_QUEUE MessageQueue
;
577 PSYSTEM_CURSORINFO CurInfo
;
579 KeQueryTickCount(&LargeTickCount
);
580 Msg
->time
= MsqCalculateMessageTime(&LargeTickCount
);
582 MouseHookData
.pt
.x
= LOWORD(Msg
->lParam
);
583 MouseHookData
.pt
.y
= HIWORD(Msg
->lParam
);
584 switch (Msg
->message
)
587 MouseHookData
.mouseData
= MAKELONG(0, GET_WHEEL_DELTA_WPARAM(Msg
->wParam
));
591 case WM_XBUTTONDBLCLK
:
592 case WM_NCXBUTTONDOWN
:
594 case WM_NCXBUTTONDBLCLK
:
595 MouseHookData
.mouseData
= MAKELONG(0, HIWORD(Msg
->wParam
));
598 MouseHookData
.mouseData
= 0;
602 MouseHookData
.flags
= flags
; // LLMHF_INJECTED
603 MouseHookData
.time
= Msg
->time
;
604 MouseHookData
.dwExtraInfo
= dwExtraInfo
;
606 /* If the hook procedure returned non zero, dont send the message */
609 if (co_HOOK_CallHooks(WH_MOUSE_LL
, HC_ACTION
, Msg
->message
, (LPARAM
) &MouseHookData
))
613 /* Get the desktop window */
614 pwndDesktop
= UserGetDesktopWindow();
615 if (!pwndDesktop
) return;
616 // pDesk = pwndDesktop->head.rpdesk;
618 /* Check if the mouse is captured */
619 Msg
->hwnd
= IntGetCaptureWindow();
620 if (Msg
->hwnd
!= NULL
)
622 pwnd
= UserGetWindowObject(Msg
->hwnd
);
626 pwnd
= IntTopLevelWindowFromPoint(Msg
->pt
.x
, Msg
->pt
.y
);
627 if (pwnd
) Msg
->hwnd
= pwnd
->head
.h
;
630 hdcScreen
= IntGetScreenDC();
631 CurInfo
= IntGetSysCursorInfo();
633 /* Check if we found a window */
634 if (Msg
->hwnd
!= NULL
&& pwnd
!= NULL
)
636 pti
= pwnd
->head
.pti
;
637 MessageQueue
= pti
->MessageQueue
;
639 if (MessageQueue
->QF_flags
& QF_INDESTROY
)
641 ERR("Mouse is over a Window with a Dead Message Queue!\n");
645 MessageQueue
->ptiMouse
= pti
;
647 if (Msg
->message
== WM_MOUSEMOVE
)
649 /* Check if cursor should be visible */
651 MessageQueue
->CursorObject
&&
652 MessageQueue
->iCursorLevel
>= 0)
654 /* Check if shape has changed */
655 if(CurInfo
->CurrentCursorObject
!= MessageQueue
->CursorObject
)
657 /* Call GDI to set the new screen cursor */
658 #ifdef NEW_CURSORICON
659 GreSetPointerShape(hdcScreen
,
660 MessageQueue
->CursorObject
->hbmAlpha
?
661 NULL
: MessageQueue
->CursorObject
->hbmMask
,
662 MessageQueue
->CursorObject
->hbmAlpha
?
663 MessageQueue
->CursorObject
->hbmAlpha
: MessageQueue
->CursorObject
->hbmColor
,
664 MessageQueue
->CursorObject
->xHotspot
,
665 MessageQueue
->CursorObject
->yHotspot
,
668 MessageQueue
->CursorObject
->hbmAlpha
? SPS_ALPHA
: 0);
670 GreSetPointerShape(hdcScreen
,
671 MessageQueue
->CursorObject
->IconInfo
.hbmMask
,
672 MessageQueue
->CursorObject
->IconInfo
.hbmColor
,
673 MessageQueue
->CursorObject
->IconInfo
.xHotspot
,
674 MessageQueue
->CursorObject
->IconInfo
.yHotspot
,
680 GreMovePointer(hdcScreen
, Msg
->pt
.x
, Msg
->pt
.y
);
682 /* Check if w have to hide cursor */
683 else if (CurInfo
->ShowingCursor
>= 0)
684 GreMovePointer(hdcScreen
, -1, -1);
686 /* Update global cursor info */
687 CurInfo
->ShowingCursor
= MessageQueue
->iCursorLevel
;
688 CurInfo
->CurrentCursorObject
= MessageQueue
->CursorObject
;
689 gpqCursor
= MessageQueue
;
691 /* Mouse move is a special case */
692 MessageQueue
->QF_flags
|= QF_MOUSEMOVED
;
693 gdwMouseMoveExtraInfo
= dwExtraInfo
;
694 gdwMouseMoveTimeStamp
= Msg
->time
;
695 MsqWakeQueue(pti
, QS_MOUSEMOVE
, TRUE
);
699 if (!IntGetCaptureWindow())
701 // ERR("ptiLastInput is set\n");
702 // ptiLastInput = pti; // Once this is set during Reboot or Shutdown, this prevents the exit window having foreground.
703 // Find all the Move Mouse calls and fix mouse set active focus issues......
706 // Post mouse move before posting mouse buttons, keep it in sync.
707 if (pti
->MessageQueue
->QF_flags
& QF_MOUSEMOVED
)
709 IntCoalesceMouseMove(pti
);
712 TRACE("Posting mouse message to hwnd=%p!\n", UserHMGetHandle(pwnd
));
713 MsqPostMessage(pti
, Msg
, TRUE
, QS_MOUSEBUTTON
, 0, dwExtraInfo
);
718 /* always show cursor on background; FIXME: set default pointer */
719 GreMovePointer(hdcScreen
, Msg
->pt
.x
, Msg
->pt
.y
);
720 CurInfo
->ShowingCursor
= 0;
724 PUSER_MESSAGE FASTCALL
725 MsqCreateMessage(LPMSG Msg
)
727 PUSER_MESSAGE Message
;
729 Message
= ExAllocateFromPagedLookasideList(pgMessageLookasideList
);
735 RtlZeroMemory(Message
, sizeof(*Message
));
736 RtlMoveMemory(&Message
->Msg
, Msg
, sizeof(MSG
));
742 MsqDestroyMessage(PUSER_MESSAGE Message
)
744 if (Message
->pti
== NULL
)
746 ERR("Double Free Message\n");
750 ExFreeToPagedLookasideList(pgMessageLookasideList
, Message
);
754 co_MsqDispatchOneSentMessage(PTHREADINFO pti
)
756 PUSER_SENT_MESSAGE SaveMsg
, Message
;
761 ASSERT(pti
== PsGetCurrentThreadWin32Thread());
763 if (IsListEmpty(&pti
->SentMessagesListHead
))
768 /* remove it from the list of pending messages */
769 Entry
= RemoveHeadList(&pti
->SentMessagesListHead
);
770 Message
= CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
);
772 SaveMsg
= pti
->pusmCurrent
;
773 pti
->pusmCurrent
= Message
;
775 // Processing a message sent to it from another thread.
776 if ( ( Message
->ptiSender
&& pti
!= Message
->ptiSender
) ||
777 ( Message
->ptiCallBackSender
&& pti
!= Message
->ptiCallBackSender
))
778 { // most likely, but, to be sure.
779 pti
->pcti
->CTI_flags
|= CTI_INSENDMESSAGE
; // Let the user know...
782 /* insert it to the list of messages that are currently dispatched by this
784 InsertTailList(&pti
->LocalDispatchingMessagesHead
,
785 &Message
->ListEntry
);
787 ClearMsgBitsMask(pti
, Message
->QS_Flags
);
789 if (Message
->HookMessage
== MSQ_ISHOOK
)
790 { // Direct Hook Call processor
791 Result
= co_CallHook( Message
->Msg
.message
, // HookId
792 (INT
)(INT_PTR
)Message
->Msg
.hwnd
, // Code
794 Message
->Msg
.lParam
);
796 else if (Message
->HookMessage
== MSQ_ISEVENT
)
797 { // Direct Event Call processor
798 Result
= co_EVENT_CallEvents( Message
->Msg
.message
,
801 Message
->Msg
.lParam
);
803 else if(Message
->HookMessage
== MSQ_INJECTMODULE
)
805 Result
= IntLoadHookModule(Message
->Msg
.message
,
806 (HHOOK
)Message
->Msg
.lParam
,
807 Message
->Msg
.wParam
);
809 else if ((Message
->CompletionCallback
) &&
810 (Message
->ptiCallBackSender
== pti
))
811 { /* Call the callback routine */
812 if (Message
->QS_Flags
& QS_SMRESULT
)
814 co_IntCallSentMessageCallback(Message
->CompletionCallback
,
816 Message
->Msg
.message
,
817 Message
->CompletionCallbackContext
,
819 /* Set callback to NULL to prevent reentry */
820 Message
->CompletionCallback
= NULL
;
824 /* The message has not been processed yet, reinsert it. */
825 RemoveEntryList(&Message
->ListEntry
);
826 InsertTailList(&Message
->ptiCallBackSender
->SentMessagesListHead
, &Message
->ListEntry
);
827 TRACE("Callback Message not processed yet. Requeuing the message\n");
833 { /* Call the window procedure. */
834 Result
= co_IntSendMessage( Message
->Msg
.hwnd
,
835 Message
->Msg
.message
,
837 Message
->Msg
.lParam
);
840 /* remove the message from the local dispatching list, because it doesn't need
841 to be cleaned up on thread termination anymore */
842 RemoveEntryList(&Message
->ListEntry
);
844 /* If the message is a callback, insert it in the callback senders MessageQueue */
845 if (Message
->CompletionCallback
)
847 if (Message
->ptiCallBackSender
)
849 Message
->lResult
= Result
;
850 Message
->QS_Flags
|= QS_SMRESULT
;
852 /* insert it in the callers message queue */
853 InsertTailList(&Message
->ptiCallBackSender
->SentMessagesListHead
, &Message
->ListEntry
);
854 MsqWakeQueue(Message
->ptiCallBackSender
, QS_SENDMESSAGE
, TRUE
);
860 /* remove the message from the dispatching list if needed, so lock the sender's message queue */
861 if (Message
->ptiSender
)
863 if (Message
->DispatchingListEntry
.Flink
!= NULL
)
865 /* only remove it from the dispatching list if not already removed by a timeout */
866 RemoveEntryList(&Message
->DispatchingListEntry
);
869 /* still keep the sender's message queue locked, so the sender can't exit the
870 MsqSendMessage() function (if timed out) */
872 if (Message
->QS_Flags
& QS_SMRESULT
)
874 Result
= Message
->lResult
;
877 /* Let the sender know the result. */
878 if (Message
->Result
!= NULL
)
880 *Message
->Result
= Result
;
883 if (Message
->HasPackedLParam
)
885 if (Message
->Msg
.lParam
)
886 ExFreePool((PVOID
)Message
->Msg
.lParam
);
889 /* Notify the sender. */
890 if (Message
->CompletionEvent
!= NULL
)
892 KeSetEvent(Message
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
895 /* free the message */
896 ExFreePoolWithTag(Message
, TAG_USRMSG
);
899 /* do not hangup on the user if this is reentering */
900 if (!SaveMsg
) pti
->pcti
->CTI_flags
&= ~CTI_INSENDMESSAGE
;
901 pti
->pusmCurrent
= SaveMsg
;
907 MsqRemoveWindowMessagesFromQueue(PWND Window
)
910 PUSER_SENT_MESSAGE SentMessage
;
911 PUSER_MESSAGE PostedMessage
;
912 PLIST_ENTRY CurrentEntry
, ListHead
;
916 pti
= Window
->head
.pti
;
918 /* remove the posted messages for this window */
919 CurrentEntry
= pti
->PostedMessagesListHead
.Flink
;
920 ListHead
= &pti
->PostedMessagesListHead
;
921 while (CurrentEntry
!= ListHead
)
923 PostedMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
925 if (PostedMessage
->Msg
.hwnd
== Window
->head
.h
)
927 RemoveEntryList(&PostedMessage
->ListEntry
);
928 ClearMsgBitsMask(pti
, PostedMessage
->QS_Flags
);
929 MsqDestroyMessage(PostedMessage
);
930 CurrentEntry
= pti
->PostedMessagesListHead
.Flink
;
934 CurrentEntry
= CurrentEntry
->Flink
;
938 /* remove the sent messages for this window */
939 CurrentEntry
= pti
->SentMessagesListHead
.Flink
;
940 ListHead
= &pti
->SentMessagesListHead
;
941 while (CurrentEntry
!= ListHead
)
943 SentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
945 if(SentMessage
->Msg
.hwnd
== Window
->head
.h
)
947 TRACE("Notify the sender and remove a message from the queue that had not been dispatched\n");
949 RemoveEntryList(&SentMessage
->ListEntry
);
950 ClearMsgBitsMask(pti
, SentMessage
->QS_Flags
);
952 /* Only if the message has a sender was the queue referenced */
953 if ((SentMessage
->ptiSender
)
954 && (SentMessage
->DispatchingListEntry
.Flink
!= NULL
))
956 RemoveEntryList(&SentMessage
->DispatchingListEntry
);
959 /* wake the sender's thread */
960 if (SentMessage
->CompletionEvent
!= NULL
)
962 KeSetEvent(SentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
965 if (SentMessage
->HasPackedLParam
)
967 if (SentMessage
->Msg
.lParam
)
968 ExFreePool((PVOID
)SentMessage
->Msg
.lParam
);
971 /* free the message */
972 ExFreePoolWithTag(SentMessage
, TAG_USRMSG
);
974 CurrentEntry
= pti
->SentMessagesListHead
.Flink
;
978 CurrentEntry
= CurrentEntry
->Flink
;
984 co_MsqSendMessageAsync(PTHREADINFO ptiReceiver
,
989 SENDASYNCPROC CompletionCallback
,
990 ULONG_PTR CompletionCallbackContext
,
991 BOOL HasPackedLParam
,
995 PTHREADINFO ptiSender
;
996 PUSER_SENT_MESSAGE Message
;
998 if(!(Message
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(USER_SENT_MESSAGE
), TAG_USRMSG
)))
1000 ERR("MsqSendMessage(): Not enough memory to allocate a message");
1004 ptiSender
= PsGetCurrentThreadWin32Thread();
1006 Message
->Msg
.hwnd
= hwnd
;
1007 Message
->Msg
.message
= Msg
;
1008 Message
->Msg
.wParam
= wParam
;
1009 Message
->Msg
.lParam
= lParam
;
1010 Message
->CompletionEvent
= NULL
;
1011 Message
->Result
= 0;
1012 Message
->lResult
= 0;
1013 Message
->ptiReceiver
= ptiReceiver
;
1014 Message
->ptiSender
= NULL
;
1015 Message
->ptiCallBackSender
= ptiSender
;
1016 Message
->DispatchingListEntry
.Flink
= NULL
;
1017 Message
->CompletionCallback
= CompletionCallback
;
1018 Message
->CompletionCallbackContext
= CompletionCallbackContext
;
1019 Message
->HookMessage
= HookMessage
;
1020 Message
->HasPackedLParam
= HasPackedLParam
;
1021 Message
->QS_Flags
= QS_SENDMESSAGE
;
1023 InsertTailList(&ptiReceiver
->SentMessagesListHead
, &Message
->ListEntry
);
1024 MsqWakeQueue(ptiReceiver
, QS_SENDMESSAGE
, TRUE
);
1030 co_MsqSendMessage(PTHREADINFO ptirec
,
1041 PUSER_SENT_MESSAGE Message
;
1042 KEVENT CompletionEvent
;
1043 NTSTATUS WaitStatus
;
1044 LARGE_INTEGER Timeout
;
1047 LRESULT Result
= 0; //// Result could be trashed. ////
1049 pti
= PsGetCurrentThreadWin32Thread();
1050 ASSERT(pti
!= ptirec
);
1051 ASSERT(ptirec
->pcti
); // Send must have a client side to receive it!!!!
1053 /* Don't send from or to a dying thread */
1054 if (pti
->TIF_flags
& TIF_INCLEANUP
|| ptirec
->TIF_flags
& TIF_INCLEANUP
)
1056 // Unless we are dying and need to tell our parents.
1057 if (pti
->TIF_flags
& TIF_INCLEANUP
&& !(ptirec
->TIF_flags
& TIF_INCLEANUP
))
1059 // Parent notify is the big one. Fire and forget!
1060 TRACE("Send message from dying thread %d\n",Msg
);
1061 co_MsqSendMessageAsync(ptirec
, Wnd
, Msg
, wParam
, lParam
, NULL
, 0, FALSE
, HookMessage
);
1063 if (uResult
) *uResult
= -1;
1064 TRACE("MsqSM: Msg %d Current pti %lu or Rec pti %lu\n", Msg
, pti
->TIF_flags
& TIF_INCLEANUP
, ptirec
->TIF_flags
& TIF_INCLEANUP
);
1065 return STATUS_UNSUCCESSFUL
;
1068 if ( HookMessage
== MSQ_NORMAL
)
1070 pWnd
= ValidateHwndNoErr(Wnd
);
1072 // These can not cross International Border lines!
1073 if ( pti
->ppi
!= ptirec
->ppi
&& pWnd
)
1077 // Handle the special case when working with password transfers across bordering processes.
1079 case EM_SETPASSWORDCHAR
:
1081 // Look for edit controls setup for passwords.
1082 if ( gpsi
->atomSysClass
[ICLS_EDIT
] == pWnd
->pcls
->atomClassName
&& // Use atomNVClassName.
1083 pWnd
->style
& ES_PASSWORD
)
1085 if (uResult
) *uResult
= -1;
1086 ERR("Running across the border without a passport!\n");
1087 EngSetLastError(ERROR_ACCESS_DENIED
);
1088 return STATUS_UNSUCCESSFUL
;
1092 if (uResult
) *uResult
= -1;
1093 ERR("Running across the border without a passport!\n");
1094 return STATUS_UNSUCCESSFUL
;
1098 // These can not cross State lines!
1099 if ( Msg
== WM_CREATE
|| Msg
== WM_NCCREATE
)
1101 if (uResult
) *uResult
= -1;
1102 ERR("Can not tell the other State we have Create!\n");
1103 return STATUS_UNSUCCESSFUL
;
1107 if(!(Message
= ExAllocatePoolWithTag(PagedPool
, sizeof(USER_SENT_MESSAGE
), TAG_USRMSG
)))
1109 ERR("MsqSendMessage(): Not enough memory to allocate a message");
1110 return STATUS_INSUFFICIENT_RESOURCES
;
1113 KeInitializeEvent(&CompletionEvent
, NotificationEvent
, FALSE
);
1115 Timeout
.QuadPart
= Int32x32To64(-10000,uTimeout
); // Pass SMTO test with a TO of 0x80000000.
1116 TRACE("Timeout val %lld\n",Timeout
.QuadPart
)
1118 /* FIXME: Increase reference counter of sender's message queue here */
1120 Message
->Msg
.hwnd
= Wnd
;
1121 Message
->Msg
.message
= Msg
;
1122 Message
->Msg
.wParam
= wParam
;
1123 Message
->Msg
.lParam
= lParam
;
1124 Message
->CompletionEvent
= &CompletionEvent
;
1125 Message
->Result
= &Result
;
1126 Message
->lResult
= 0;
1127 Message
->QS_Flags
= 0;
1128 Message
->ptiReceiver
= ptirec
;
1129 Message
->ptiSender
= pti
;
1130 Message
->ptiCallBackSender
= NULL
;
1131 Message
->CompletionCallback
= NULL
;
1132 Message
->CompletionCallbackContext
= 0;
1133 Message
->HookMessage
= HookMessage
;
1134 Message
->HasPackedLParam
= FALSE
;
1136 /* Add it to the list of pending messages */
1137 InsertTailList(&pti
->DispatchingMessagesHead
, &Message
->DispatchingListEntry
);
1139 /* Queue it in the destination's message queue */
1140 InsertTailList(&ptirec
->SentMessagesListHead
, &Message
->ListEntry
);
1142 Message
->QS_Flags
= QS_SENDMESSAGE
;
1143 MsqWakeQueue(ptirec
, QS_SENDMESSAGE
, TRUE
);
1145 /* We can't access the Message anymore since it could have already been deleted! */
1149 PVOID WaitObjects
[2];
1151 WaitObjects
[0] = &CompletionEvent
; // Wait 0
1152 WaitObjects
[1] = ptirec
->pEThread
; // Wait 1
1156 WaitStatus
= KeWaitForMultipleObjects(2, WaitObjects
, WaitAny
, UserRequest
,
1157 UserMode
, FALSE
, (uTimeout
? &Timeout
: NULL
), NULL
);
1161 if (WaitStatus
== STATUS_TIMEOUT
|| WaitStatus
== STATUS_USER_APC
)
1163 /* Look up if the message has not yet dispatched, if so
1164 make sure it can't pass a result and it must not set the completion event anymore */
1165 Entry
= ptirec
->SentMessagesListHead
.Flink
;
1166 while (Entry
!= &ptirec
->SentMessagesListHead
)
1168 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
)
1171 /* We can access Message here, it's secure because the message queue is locked
1172 and the message is still hasn't been dispatched */
1173 Message
->CompletionEvent
= NULL
;
1174 Message
->Result
= NULL
;
1177 Entry
= Entry
->Flink
;
1180 /* Remove from the local dispatching list so the other thread knows,
1181 it can't pass a result and it must not set the completion event anymore */
1182 Entry
= pti
->DispatchingMessagesHead
.Flink
;
1183 while (Entry
!= &pti
->DispatchingMessagesHead
)
1185 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, DispatchingListEntry
)
1188 /* We can access Message here, it's secure because the sender's message is locked
1189 and the message has definitely not yet been destroyed, otherwise it would
1190 have been removed from this list by the dispatching routine right after
1191 dispatching the message */
1192 Message
->CompletionEvent
= NULL
;
1193 Message
->Result
= NULL
;
1194 RemoveEntryList(&Message
->DispatchingListEntry
);
1195 Message
->DispatchingListEntry
.Flink
= NULL
;
1198 Entry
= Entry
->Flink
;
1201 TRACE("MsqSendMessage (blocked) timed out 1 Status %p\n",WaitStatus
);
1204 // Receiving thread passed on and left us hanging with issues still pending.
1205 if ( WaitStatus
== STATUS_WAIT_1
)
1207 ERR("Bk Receiving Thread woken up dead!\n");
1208 Entry
= pti
->DispatchingMessagesHead
.Flink
;
1209 while (Entry
!= &pti
->DispatchingMessagesHead
)
1211 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, DispatchingListEntry
)
1214 Message
->CompletionEvent
= NULL
;
1215 Message
->Result
= NULL
;
1216 RemoveEntryList(&Message
->DispatchingListEntry
);
1217 Message
->DispatchingListEntry
.Flink
= NULL
;
1220 Entry
= Entry
->Flink
;
1223 while (co_MsqDispatchOneSentMessage(pti
))
1228 PVOID WaitObjects
[3];
1230 WaitObjects
[0] = &CompletionEvent
; // Wait 0
1231 WaitObjects
[1] = pti
->pEventQueueServer
; // Wait 1
1232 WaitObjects
[2] = ptirec
->pEThread
; // Wait 2
1238 WaitStatus
= KeWaitForMultipleObjects(3, WaitObjects
, WaitAny
, UserRequest
,
1239 UserMode
, FALSE
, (uTimeout
? &Timeout
: NULL
), NULL
);
1243 if (WaitStatus
== STATUS_TIMEOUT
|| WaitStatus
== STATUS_USER_APC
)
1245 /* Look up if the message has not yet been dispatched, if so
1246 make sure it can't pass a result and it must not set the completion event anymore */
1247 Entry
= ptirec
->SentMessagesListHead
.Flink
;
1248 while (Entry
!= &ptirec
->SentMessagesListHead
)
1250 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
)
1253 /* We can access Message here, it's secure because the message queue is locked
1254 and the message is still hasn't been dispatched */
1255 Message
->CompletionEvent
= NULL
;
1256 Message
->Result
= NULL
;
1259 Entry
= Entry
->Flink
;
1262 /* Remove from the local dispatching list so the other thread knows,
1263 it can't pass a result and it must not set the completion event anymore */
1264 Entry
= pti
->DispatchingMessagesHead
.Flink
;
1265 while (Entry
!= &pti
->DispatchingMessagesHead
)
1267 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, DispatchingListEntry
)
1270 /* We can access Message here, it's secure because the sender's message is locked
1271 and the message has definitely not yet been destroyed, otherwise it would
1272 have been removed from this list by the dispatching routine right after
1273 dispatching the message */
1274 Message
->CompletionEvent
= NULL
;
1275 Message
->Result
= NULL
;
1276 RemoveEntryList(&Message
->DispatchingListEntry
);
1277 Message
->DispatchingListEntry
.Flink
= NULL
;
1280 Entry
= Entry
->Flink
;
1283 TRACE("MsqSendMessage timed out 2 Status %p\n",WaitStatus
);
1287 // Receiving thread passed on and left us hanging with issues still pending.
1288 if ( WaitStatus
== STATUS_WAIT_2
)
1290 ERR("NB Receiving Thread woken up dead!\n");
1291 Entry
= pti
->DispatchingMessagesHead
.Flink
;
1292 while (Entry
!= &pti
->DispatchingMessagesHead
)
1294 if ((PUSER_SENT_MESSAGE
) CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, DispatchingListEntry
)
1297 Message
->CompletionEvent
= NULL
;
1298 Message
->Result
= NULL
;
1299 RemoveEntryList(&Message
->DispatchingListEntry
);
1300 Message
->DispatchingListEntry
.Flink
= NULL
;
1303 Entry
= Entry
->Flink
;
1306 while (co_MsqDispatchOneSentMessage(pti
))
1309 while (NT_SUCCESS(WaitStatus
) && WaitStatus
== STATUS_WAIT_1
);
1312 if ( WaitStatus
== STATUS_USER_APC
)
1314 // The current thread is dying!
1315 TRACE("User APC\n");
1316 co_IntDeliverUserAPC();
1317 ERR("User APC Returned\n"); // Should not see this message.
1320 if ( WaitStatus
!= STATUS_TIMEOUT
)
1324 *uResult
= (STATUS_WAIT_0
== WaitStatus
? Result
: -1);
1332 MsqPostMessage(PTHREADINFO pti
,
1334 BOOLEAN HardwareMessage
,
1339 PUSER_MESSAGE Message
;
1340 PUSER_MESSAGE_QUEUE MessageQueue
;
1342 if ( pti
->TIF_flags
& TIF_INCLEANUP
|| pti
->MessageQueue
->QF_flags
& QF_INDESTROY
)
1344 ERR("Post Msg; Thread or Q is Dead!\n");
1348 if(!(Message
= MsqCreateMessage(Msg
)))
1353 MessageQueue
= pti
->MessageQueue
;
1357 ERR("Post Msg; System Qeued Event Message!\n");
1358 InsertHeadList(&pti
->PostedMessagesListHead
, &Message
->ListEntry
);
1360 else if (!HardwareMessage
)
1362 InsertTailList(&pti
->PostedMessagesListHead
, &Message
->ListEntry
);
1366 InsertTailList(&MessageQueue
->HardwareMessagesListHead
, &Message
->ListEntry
);
1369 if (Msg
->message
== WM_HOTKEY
) MessageBits
|= QS_HOTKEY
; // Justin Case, just set it.
1370 Message
->dwQEvent
= dwQEvent
;
1371 Message
->ExtraInfo
= ExtraInfo
;
1372 Message
->QS_Flags
= MessageBits
;
1374 MsqWakeQueue(pti
, MessageBits
, TRUE
);
1378 MsqPostQuitMessage(PTHREADINFO pti
, ULONG ExitCode
)
1380 pti
->QuitPosted
= TRUE
;
1381 pti
->exitCode
= ExitCode
;
1382 MsqWakeQueue(pti
, QS_POSTMESSAGE
|QS_ALLPOSTMESSAGE
, TRUE
);
1385 /***********************************************************************
1386 * MsqSendParentNotify
1388 * Send a WM_PARENTNOTIFY to all ancestors of the given window, unless
1389 * the window has the WS_EX_NOPARENTNOTIFY style.
1391 static void MsqSendParentNotify( PWND pwnd
, WORD event
, WORD idChild
, POINT pt
)
1393 PWND pwndDesktop
= UserGetDesktopWindow();
1395 /* pt has to be in the client coordinates of the parent window */
1396 pt
.x
+= pwndDesktop
->rcClient
.left
- pwnd
->rcClient
.left
;
1397 pt
.y
+= pwndDesktop
->rcClient
.top
- pwnd
->rcClient
.top
;
1403 if (!(pwnd
->style
& WS_CHILD
)) break;
1404 if (pwnd
->ExStyle
& WS_EX_NOPARENTNOTIFY
) break;
1405 if (!(pwndParent
= IntGetParent(pwnd
))) break;
1406 if (pwndParent
== pwndDesktop
) break;
1407 pt
.x
+= pwnd
->rcClient
.left
- pwndParent
->rcClient
.left
;
1408 pt
.y
+= pwnd
->rcClient
.top
- pwndParent
->rcClient
.top
;
1411 co_IntSendMessage( UserHMGetHandle(pwnd
), WM_PARENTNOTIFY
,
1412 MAKEWPARAM( event
, idChild
), MAKELPARAM( pt
.x
, pt
.y
) );
1418 IntTrackMouseMove(PWND pwndTrack
, PDESKTOP pDesk
, PMSG msg
, USHORT hittest
)
1420 // PWND pwndTrack = IntChildrenWindowFromPoint(pwndMsg, msg->pt.x, msg->pt.y);
1421 // hittest = (USHORT)GetNCHitEx(pwndTrack, msg->pt); /// @todo WTF is this???
1423 if ( pDesk
->spwndTrack
!= pwndTrack
|| // Change with tracking window or
1424 msg
->message
!= WM_MOUSEMOVE
|| // Mouse click changes or
1425 pDesk
->htEx
!= hittest
) // Change in current hit test states.
1427 TRACE("ITMM: Track Mouse Move!\n");
1429 /* Handle only the changing window track and mouse move across a border. */
1430 if ( pDesk
->spwndTrack
!= pwndTrack
||
1431 (pDesk
->htEx
== HTCLIENT
) ^ (hittest
== HTCLIENT
) )
1433 TRACE("ITMM: Another Wnd %d or Across Border %d\n",
1434 pDesk
->spwndTrack
!= pwndTrack
,(pDesk
->htEx
== HTCLIENT
) ^ (hittest
== HTCLIENT
));
1436 if ( pDesk
->dwDTFlags
& DF_TME_LEAVE
)
1437 UserPostMessage( UserHMGetHandle(pDesk
->spwndTrack
),
1438 (pDesk
->htEx
!= HTCLIENT
) ? WM_NCMOUSELEAVE
: WM_MOUSELEAVE
,
1441 if ( pDesk
->dwDTFlags
& DF_TME_HOVER
)
1442 IntKillTimer(pDesk
->spwndTrack
, ID_EVENT_SYSTIMER_MOUSEHOVER
, TRUE
);
1444 /* Clear the flags to sign a change. */
1445 pDesk
->dwDTFlags
&= ~(DF_TME_LEAVE
|DF_TME_HOVER
);
1447 /* Set the Track window and hit test. */
1448 pDesk
->spwndTrack
= pwndTrack
;
1449 pDesk
->htEx
= hittest
;
1452 /* Reset, Same Track window, Hover set and Mouse Clicks or Clobbered Hover box. */
1453 if ( pDesk
->spwndTrack
== pwndTrack
&&
1454 ( msg
->message
!= WM_MOUSEMOVE
|| !RECTL_bPointInRect(&pDesk
->rcMouseHover
, msg
->pt
.x
, msg
->pt
.y
)) &&
1455 pDesk
->dwDTFlags
& DF_TME_HOVER
)
1457 TRACE("ITMM: Reset Hover points!\n");
1458 // Restart timer for the hover period.
1459 IntSetTimer(pDesk
->spwndTrack
, ID_EVENT_SYSTIMER_MOUSEHOVER
, pDesk
->dwMouseHoverTime
, SystemTimerProc
, TMRF_SYSTEM
);
1460 // Reset desktop mouse hover from the system default hover rectangle.
1461 RECTL_vSetRect(&pDesk
->rcMouseHover
,
1462 msg
->pt
.x
- gspv
.iMouseHoverWidth
/ 2,
1463 msg
->pt
.y
- gspv
.iMouseHoverHeight
/ 2,
1464 msg
->pt
.x
+ gspv
.iMouseHoverWidth
/ 2,
1465 msg
->pt
.y
+ gspv
.iMouseHoverHeight
/ 2);
1470 co_IntFindChildWindowToOwner(PWND Root
, PWND Owner
)
1473 PWND Child
, OwnerWnd
;
1475 for(Child
= Root
->spwndChild
; Child
; Child
= Child
->spwndNext
)
1477 OwnerWnd
= Child
->spwndOwner
;
1481 if(OwnerWnd
== Owner
)
1490 BOOL
co_IntProcessMouseMessage(MSG
* msg
, BOOL
* RemoveMessages
, UINT first
, UINT last
)
1497 MOUSEHOOKSTRUCT hook
;
1498 BOOL eatMsg
= FALSE
;
1500 PWND pwndMsg
, pwndDesktop
, pwndPopUP
;
1501 PUSER_MESSAGE_QUEUE MessageQueue
;
1503 PSYSTEM_CURSORINFO CurInfo
;
1505 DECLARE_RETURN(BOOL
);
1507 pti
= PsGetCurrentThreadWin32Thread();
1508 pwndDesktop
= UserGetDesktopWindow();
1509 MessageQueue
= pti
->MessageQueue
;
1510 CurInfo
= IntGetSysCursorInfo();
1511 pwndPopUP
= pwndMsg
= ValidateHwndNoErr(msg
->hwnd
);
1512 clk_msg
= MessageQueue
->msgDblClk
;
1513 pDesk
= pwndDesktop
->head
.rpdesk
;
1515 /* find the window to dispatch this mouse message to */
1516 if (MessageQueue
->spwndCapture
)
1519 pwndMsg
= MessageQueue
->spwndCapture
;
1520 if (pwndMsg
) UserReferenceObject(pwndMsg
);
1525 Start with null window. See wine win.c:test_mouse_input:WM_COMMAND tests.
1527 pwndMsg
= co_WinPosWindowFromPoint( NULL
, &msg
->pt
, &hittest
, FALSE
);
1529 // CORE-6129, Override if a diabled window with a visible popup was selected.
1531 if (pwndPopUP
&& pwndPopUP
->style
& WS_DISABLED
)
1533 TRACE("window disabled\n");
1534 pwndPopUP
= co_IntFindChildWindowToOwner(UserGetDesktopWindow(), pwndPopUP
);
1536 pwndPopUP
->style
& WS_POPUP
&&
1537 pwndPopUP
->style
& WS_VISIBLE
&&
1538 (pwndPopUP
->head
.pti
->MessageQueue
!= gpqForeground
||
1539 pwndPopUP
->head
.pti
->MessageQueue
->spwndActive
!= pwndPopUP
) &&
1540 //pwndPopUP != pwndPopUP->head.rpdesk->pDeskInfo->spwndShell needs testing.
1541 pwndPopUP
!= ValidateHwndNoErr(InputWindowStation
->ShellWindow
) )
1543 TRACE("Found Popup!\n");
1544 UserDereferenceObject(pwndMsg
);
1545 pwndMsg
= pwndPopUP
;
1546 UserReferenceObject(pwndMsg
);
1551 TRACE("Got mouse message for %p, hittest: 0x%x\n", msg
->hwnd
, hittest
);
1553 // Null window or not the same "Hardware" message queue.
1554 if (pwndMsg
== NULL
|| pwndMsg
->head
.pti
->MessageQueue
!= pti
->MessageQueue
)
1556 /* Remove and ignore the message */
1557 *RemoveMessages
= TRUE
;
1561 if ( MessageQueue
== gpqCursor
) // Cursor must use the same Queue!
1563 IntTrackMouseMove(pwndMsg
, pDesk
, msg
, hittest
);
1567 ERR("Not the same cursor!\n");
1570 msg
->hwnd
= UserHMGetHandle(pwndMsg
);
1573 message
= msg
->message
;
1574 /* Note: windows has no concept of a non-client wheel message */
1575 if (message
!= WM_MOUSEWHEEL
)
1577 if (hittest
!= HTCLIENT
)
1579 message
+= WM_NCMOUSEMOVE
- WM_MOUSEMOVE
;
1580 msg
->wParam
= hittest
; // Caution! This might break wParam check in DblClk.
1584 /* coordinates don't get translated while tracking a menu */
1585 /* FIXME: should differentiate popups and top-level menus */
1586 if (!(MessageQueue
->MenuOwner
))
1588 pt
.x
+= pwndDesktop
->rcClient
.left
- pwndMsg
->rcClient
.left
;
1589 pt
.y
+= pwndDesktop
->rcClient
.top
- pwndMsg
->rcClient
.top
;
1593 msg
->lParam
= MAKELONG( pt
.x
, pt
.y
);
1595 /* translate double clicks */
1597 if ((msg
->message
== WM_LBUTTONDOWN
) ||
1598 (msg
->message
== WM_RBUTTONDOWN
) ||
1599 (msg
->message
== WM_MBUTTONDOWN
) ||
1600 (msg
->message
== WM_XBUTTONDOWN
))
1602 BOOL update
= *RemoveMessages
;
1604 /* translate double clicks -
1605 * note that ...MOUSEMOVEs can slip in between
1606 * ...BUTTONDOWN and ...BUTTONDBLCLK messages */
1608 if ((MessageQueue
->MenuOwner
|| MessageQueue
->MoveSize
) ||
1609 hittest
!= HTCLIENT
||
1610 (pwndMsg
->pcls
->style
& CS_DBLCLKS
))
1612 if ((msg
->message
== clk_msg
.message
) &&
1613 (msg
->hwnd
== clk_msg
.hwnd
) &&
1614 // Only worry about XButton wParam.
1615 (msg
->message
!= WM_XBUTTONDOWN
|| GET_XBUTTON_WPARAM(msg
->wParam
) == GET_XBUTTON_WPARAM(clk_msg
.wParam
)) &&
1616 ((msg
->time
- clk_msg
.time
) < (ULONG
)gspv
.iDblClickTime
) &&
1617 (abs(msg
->pt
.x
- clk_msg
.pt
.x
) < UserGetSystemMetrics(SM_CXDOUBLECLK
)/2) &&
1618 (abs(msg
->pt
.y
- clk_msg
.pt
.y
) < UserGetSystemMetrics(SM_CYDOUBLECLK
)/2))
1620 message
+= (WM_LBUTTONDBLCLK
- WM_LBUTTONDOWN
);
1623 MessageQueue
->msgDblClk
.message
= 0; /* clear the double click conditions */
1629 if (!((first
== 0 && last
== 0) || (message
>= first
|| message
<= last
)))
1631 TRACE("Message out of range!!!\n");
1635 /* update static double click conditions */
1636 if (update
) MessageQueue
->msgDblClk
= *msg
;
1640 if (!((first
== 0 && last
== 0) || (message
>= first
|| message
<= last
)))
1642 TRACE("Message out of range!!!\n");
1646 // Update mouse move down keys.
1647 if (message
== WM_MOUSEMOVE
)
1649 msg
->wParam
= MsqGetDownKeyState(MessageQueue
);
1653 if(gspv
.bMouseClickLock
)
1655 BOOL IsClkLck
= FALSE
;
1657 if(msg
->message
== WM_LBUTTONUP
)
1659 IsClkLck
= ((msg
->time
- CurInfo
->ClickLockTime
) >= gspv
.dwMouseClickLockTime
);
1660 if (IsClkLck
&& (!CurInfo
->ClickLockActive
))
1662 CurInfo
->ClickLockActive
= TRUE
;
1665 else if (msg
->message
== WM_LBUTTONDOWN
)
1667 if (CurInfo
->ClickLockActive
)
1670 CurInfo
->ClickLockActive
= FALSE
;
1673 CurInfo
->ClickLockTime
= msg
->time
;
1678 /* Remove and ignore the message */
1679 *RemoveMessages
= TRUE
;
1680 TRACE("Remove and ignore the message\n");
1685 /* message is accepted now (but may still get dropped) */
1687 event
.message
= msg
->message
;
1688 event
.time
= msg
->time
;
1689 event
.hwnd
= msg
->hwnd
;
1690 event
.paramL
= msg
->pt
.x
;
1691 event
.paramH
= msg
->pt
.y
;
1692 co_HOOK_CallHooks( WH_JOURNALRECORD
, HC_ACTION
, 0, (LPARAM
)&event
);
1695 hook
.hwnd
= msg
->hwnd
;
1696 hook
.wHitTestCode
= hittest
;
1697 hook
.dwExtraInfo
= 0 /* extra_info */ ;
1698 if (co_HOOK_CallHooks( WH_MOUSE
, *RemoveMessages
? HC_ACTION
: HC_NOREMOVE
,
1699 message
, (LPARAM
)&hook
))
1702 hook
.hwnd
= msg
->hwnd
;
1703 hook
.wHitTestCode
= hittest
;
1704 hook
.dwExtraInfo
= 0 /* extra_info */ ;
1705 co_HOOK_CallHooks( WH_CBT
, HCBT_CLICKSKIPPED
, message
, (LPARAM
)&hook
);
1707 ERR("WH_MOUSE dropped mouse message!\n");
1709 /* Remove and skip message */
1710 *RemoveMessages
= TRUE
;
1714 if ((hittest
== HTERROR
) || (hittest
== HTNOWHERE
))
1716 co_IntSendMessage( msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)msg
->hwnd
,
1717 MAKELONG( hittest
, msg
->message
));
1719 /* Remove and skip message */
1720 *RemoveMessages
= TRUE
;
1724 if ((*RemoveMessages
== FALSE
) || MessageQueue
->spwndCapture
)
1726 /* Accept the message */
1727 msg
->message
= message
;
1731 if ((msg
->message
== WM_LBUTTONDOWN
) ||
1732 (msg
->message
== WM_RBUTTONDOWN
) ||
1733 (msg
->message
== WM_MBUTTONDOWN
) ||
1734 (msg
->message
== WM_XBUTTONDOWN
))
1736 /* Send the WM_PARENTNOTIFY,
1737 * note that even for double/nonclient clicks
1738 * notification message is still WM_L/M/RBUTTONDOWN.
1740 MsqSendParentNotify(pwndMsg
, msg
->message
, 0, msg
->pt
);
1742 /* Activate the window if needed */
1744 if (pwndMsg
!= MessageQueue
->spwndActive
)
1746 PWND pwndTop
= pwndMsg
;
1747 pwndTop
= IntGetNonChildAncestor(pwndTop
);
1749 if (pwndTop
&& pwndTop
!= pwndDesktop
)
1751 LONG ret
= co_IntSendMessage( msg
->hwnd
,
1753 (WPARAM
)UserHMGetHandle(pwndTop
),
1754 MAKELONG( hittest
, msg
->message
));
1757 case MA_NOACTIVATEANDEAT
:
1762 case MA_ACTIVATEANDEAT
:
1767 if (!co_IntMouseActivateWindow( pwndTop
)) eatMsg
= TRUE
;
1770 ERR( "unknown WM_MOUSEACTIVATE code %d\n", ret
);
1777 /* send the WM_SETCURSOR message */
1779 /* Windows sends the normal mouse message as the message parameter
1780 in the WM_SETCURSOR message even if it's non-client mouse message */
1781 co_IntSendMessage( msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)msg
->hwnd
, MAKELONG( hittest
, msg
->message
));
1783 msg
->message
= message
;
1788 UserDereferenceObject(pwndMsg
);
1793 BOOL
co_IntProcessKeyboardMessage(MSG
* Msg
, BOOL
* RemoveMessages
)
1796 USER_REFERENCE_ENTRY Ref
;
1800 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
1802 if (Msg
->message
== VK_PACKET
)
1804 pti
->wchInjected
= HIWORD(Msg
->wParam
);
1807 if (Msg
->message
== WM_KEYDOWN
|| Msg
->message
== WM_SYSKEYDOWN
||
1808 Msg
->message
== WM_KEYUP
|| Msg
->message
== WM_SYSKEYUP
)
1810 switch (Msg
->wParam
)
1812 case VK_LSHIFT
: case VK_RSHIFT
:
1813 Msg
->wParam
= VK_SHIFT
;
1815 case VK_LCONTROL
: case VK_RCONTROL
:
1816 Msg
->wParam
= VK_CONTROL
;
1818 case VK_LMENU
: case VK_RMENU
:
1819 Msg
->wParam
= VK_MENU
;
1824 pWnd
= ValidateHwndNoErr(Msg
->hwnd
);
1825 if (pWnd
) UserRefObjectCo(pWnd
, &Ref
);
1827 Event
.message
= Msg
->message
;
1828 Event
.hwnd
= Msg
->hwnd
;
1829 Event
.time
= Msg
->time
;
1830 Event
.paramL
= (Msg
->wParam
& 0xFF) | (HIWORD(Msg
->lParam
) << 8);
1831 Event
.paramH
= Msg
->lParam
& 0x7FFF;
1832 if (HIWORD(Msg
->lParam
) & 0x0100) Event
.paramH
|= 0x8000;
1833 co_HOOK_CallHooks( WH_JOURNALRECORD
, HC_ACTION
, 0, (LPARAM
)&Event
);
1835 if (*RemoveMessages
)
1837 if ((Msg
->message
== WM_KEYDOWN
) &&
1838 (Msg
->hwnd
!= IntGetDesktopWindow()))
1840 /* Handle F1 key by sending out WM_HELP message */
1841 if (Msg
->wParam
== VK_F1
)
1843 UserPostMessage( Msg
->hwnd
, WM_KEYF1
, 0, 0 );
1845 else if (Msg
->wParam
>= VK_BROWSER_BACK
&&
1846 Msg
->wParam
<= VK_LAUNCH_APP2
)
1848 /* FIXME: Process keystate */
1849 co_IntSendMessage(Msg
->hwnd
, WM_APPCOMMAND
, (WPARAM
)Msg
->hwnd
, MAKELPARAM(0, (FAPPCOMMAND_KEY
| (Msg
->wParam
- VK_BROWSER_BACK
+ 1))));
1852 else if (Msg
->message
== WM_KEYUP
)
1854 /* Handle VK_APPS key by posting a WM_CONTEXTMENU message */
1855 if (Msg
->wParam
== VK_APPS
&& pti
->MessageQueue
->MenuOwner
== NULL
)
1856 UserPostMessage( Msg
->hwnd
, WM_CONTEXTMENU
, (WPARAM
)Msg
->hwnd
, -1 );
1860 if (co_HOOK_CallHooks( WH_KEYBOARD
,
1861 *RemoveMessages
? HC_ACTION
: HC_NOREMOVE
,
1862 LOWORD(Msg
->wParam
),
1865 /* skip this message */
1866 co_HOOK_CallHooks( WH_CBT
,
1868 LOWORD(Msg
->wParam
),
1871 ERR("KeyboardMessage WH_KEYBOARD Call Hook return!\n");
1873 *RemoveMessages
= TRUE
;
1878 if ( pWnd
&& Ret
&& *RemoveMessages
&& Msg
->message
== WM_KEYDOWN
&& !(pti
->TIF_flags
& TIF_DISABLEIME
))
1880 if ( (ImmRet
= IntImmProcessKey(pti
->MessageQueue
, pWnd
, Msg
->message
, Msg
->wParam
, Msg
->lParam
)) )
1882 if ( ImmRet
& (IPHK_HOTKEY
|IPHK_SKIPTHISKEY
) )
1886 if ( ImmRet
& IPHK_PROCESSBYIME
)
1888 Msg
->wParam
= VK_PROCESSKEY
;
1893 if (pWnd
) UserDerefObjectCo(pWnd
);
1897 BOOL
co_IntProcessHardwareMessage(MSG
* Msg
, BOOL
* RemoveMessages
, UINT first
, UINT last
)
1899 if ( IS_MOUSE_MESSAGE(Msg
->message
))
1901 return co_IntProcessMouseMessage(Msg
, RemoveMessages
, first
, last
);
1903 else if ( IS_KBD_MESSAGE(Msg
->message
))
1905 return co_IntProcessKeyboardMessage(Msg
, RemoveMessages
);
1911 /* check whether a message filter contains at least one potential hardware message */
1913 filter_contains_hw_range( UINT first
, UINT last
)
1915 /* hardware message ranges are (in numerical order):
1916 * WM_NCMOUSEFIRST .. WM_NCMOUSELAST
1917 * WM_KEYFIRST .. WM_KEYLAST
1918 * WM_MOUSEFIRST .. WM_MOUSELAST
1921 if (last
< WM_NCMOUSEFIRST
) return 0;
1922 if (first
> WM_NCMOUSELAST
&& last
< WM_KEYFIRST
) return 0;
1923 if (first
> WM_KEYLAST
&& last
< WM_MOUSEFIRST
) return 0;
1924 if (first
> WM_MOUSELAST
) return 0;
1929 co_MsqPeekHardwareMessage(IN PTHREADINFO pti
,
1932 IN UINT MsgFilterLow
,
1933 IN UINT MsgFilterHigh
,
1938 PUSER_MESSAGE CurrentMessage
;
1939 PLIST_ENTRY ListHead
;
1944 PUSER_MESSAGE_QUEUE MessageQueue
= pti
->MessageQueue
;
1946 if (!filter_contains_hw_range( MsgFilterLow
, MsgFilterHigh
)) return FALSE
;
1948 ListHead
= MessageQueue
->HardwareMessagesListHead
.Flink
;
1950 if (IsListEmpty(ListHead
)) return FALSE
;
1952 if (!MessageQueue
->ptiSysLock
)
1954 MessageQueue
->ptiSysLock
= pti
;
1955 pti
->pcti
->CTI_flags
|= CTI_THREADSYSLOCK
;
1958 if (MessageQueue
->ptiSysLock
!= pti
)
1960 ERR("MsqPeekHardwareMessage: Thread Q is locked to another pti!\n");
1964 while (ListHead
!= &MessageQueue
->HardwareMessagesListHead
)
1966 CurrentMessage
= CONTAINING_RECORD(ListHead
, USER_MESSAGE
, ListEntry
);
1967 ListHead
= ListHead
->Flink
;
1969 if (MessageQueue
->idSysPeek
== (ULONG_PTR
)CurrentMessage
)
1971 TRACE("Skip this message due to it is in play!\n");
1976 1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL.
1977 2: retrieves only messages on the current thread's message queue whose hwnd value is NULL.
1978 3: handle to the window whose messages are to be retrieved.
1980 if ( ( !Window
|| // 1
1981 ( Window
== PWND_BOTTOM
&& CurrentMessage
->Msg
.hwnd
== NULL
) || // 2
1982 ( Window
!= PWND_BOTTOM
&& Window
->head
.h
== CurrentMessage
->Msg
.hwnd
) || // 3
1983 ( CurrentMessage
->Msg
.message
== WM_MOUSEMOVE
) ) && // Null window for mouse moves.
1984 ( ( ( MsgFilterLow
== 0 && MsgFilterHigh
== 0 ) && CurrentMessage
->QS_Flags
& QSflags
) ||
1985 ( MsgFilterLow
<= CurrentMessage
->Msg
.message
&& MsgFilterHigh
>= CurrentMessage
->Msg
.message
) ) )
1987 idSave
= MessageQueue
->idSysPeek
;
1988 MessageQueue
->idSysPeek
= (ULONG_PTR
)CurrentMessage
;
1990 msg
= CurrentMessage
->Msg
;
1991 QS_Flags
= CurrentMessage
->QS_Flags
;
1993 UpdateKeyStateFromMsg(MessageQueue
, &msg
);
1994 AcceptMessage
= co_IntProcessHardwareMessage(&msg
, &Remove
, MsgFilterLow
, MsgFilterHigh
);
1998 if (CurrentMessage
->pti
!= NULL
)
2000 RemoveEntryList(&CurrentMessage
->ListEntry
);
2001 MsqDestroyMessage(CurrentMessage
);
2003 ClearMsgBitsMask(pti
, QS_Flags
);
2006 MessageQueue
->idSysPeek
= idSave
;
2017 MessageQueue
->ptiSysLock
= NULL
;
2018 pti
->pcti
->CTI_flags
&= ~CTI_THREADSYSLOCK
;
2023 MsqPeekMessage(IN PTHREADINFO pti
,
2026 IN UINT MsgFilterLow
,
2027 IN UINT MsgFilterHigh
,
2029 OUT LONG_PTR
*ExtraInfo
,
2032 PUSER_MESSAGE CurrentMessage
;
2033 PLIST_ENTRY ListHead
;
2037 ListHead
= pti
->PostedMessagesListHead
.Flink
;
2039 if (IsListEmpty(ListHead
)) return FALSE
;
2041 while(ListHead
!= &pti
->PostedMessagesListHead
)
2043 CurrentMessage
= CONTAINING_RECORD(ListHead
, USER_MESSAGE
, ListEntry
);
2044 ListHead
= ListHead
->Flink
;
2047 1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL.
2048 2: retrieves only messages on the current thread's message queue whose hwnd value is NULL.
2049 3: handle to the window whose messages are to be retrieved.
2051 if ( ( !Window
|| // 1
2052 ( Window
== PWND_BOTTOM
&& CurrentMessage
->Msg
.hwnd
== NULL
) || // 2
2053 ( Window
!= PWND_BOTTOM
&& Window
->head
.h
== CurrentMessage
->Msg
.hwnd
) ) && // 3
2054 ( ( ( MsgFilterLow
== 0 && MsgFilterHigh
== 0 ) && CurrentMessage
->QS_Flags
& QSflags
) ||
2055 ( MsgFilterLow
<= CurrentMessage
->Msg
.message
&& MsgFilterHigh
>= CurrentMessage
->Msg
.message
) ) )
2057 *Message
= CurrentMessage
->Msg
;
2058 *ExtraInfo
= CurrentMessage
->ExtraInfo
;
2059 QS_Flags
= CurrentMessage
->QS_Flags
;
2063 if (CurrentMessage
->pti
!= NULL
)
2065 RemoveEntryList(&CurrentMessage
->ListEntry
);
2066 MsqDestroyMessage(CurrentMessage
);
2068 ClearMsgBitsMask(pti
, QS_Flags
);
2079 co_MsqWaitForNewMessages(PTHREADINFO pti
, PWND WndFilter
,
2080 UINT MsgFilterMin
, UINT MsgFilterMax
)
2084 ret
= KeWaitForSingleObject( pti
->pEventQueueServer
,
2090 if ( ret
== STATUS_USER_APC
)
2092 TRACE("MWFNW User APC\n");
2093 co_IntDeliverUserAPC();
2099 MsqIsHung(PTHREADINFO pti
)
2101 LARGE_INTEGER LargeTickCount
;
2103 KeQueryTickCount(&LargeTickCount
);
2104 return ((LargeTickCount
.u
.LowPart
- pti
->timeLast
) > MSQ_HUNG
);
2109 HungAppSysTimerProc(HWND hwnd
, UINT uMsg
, UINT_PTR idEvent
, DWORD dwTime
)
2112 TRACE("HungAppSysTimerProc\n");
2113 // Process list of windows that are hung and waiting.
2117 MsqInitializeMessageQueue(PTHREADINFO pti
, PUSER_MESSAGE_QUEUE MessageQueue
)
2119 MessageQueue
->CaretInfo
= (PTHRDCARETINFO
)(MessageQueue
+ 1);
2120 InitializeListHead(&MessageQueue
->HardwareMessagesListHead
); // Keep here!
2121 MessageQueue
->spwndFocus
= NULL
;
2122 MessageQueue
->iCursorLevel
= 0;
2123 MessageQueue
->CursorObject
= NULL
;
2124 RtlCopyMemory(MessageQueue
->afKeyState
, gafAsyncKeyState
, sizeof(gafAsyncKeyState
));
2125 MessageQueue
->ptiMouse
= pti
;
2126 MessageQueue
->ptiKeyboard
= pti
;
2127 MessageQueue
->cThreads
++;
2133 MsqCleanupThreadMsgs(PTHREADINFO pti
)
2135 PLIST_ENTRY CurrentEntry
;
2136 PUSER_MESSAGE CurrentMessage
;
2137 PUSER_SENT_MESSAGE CurrentSentMessage
;
2139 /* cleanup posted messages */
2140 while (!IsListEmpty(&pti
->PostedMessagesListHead
))
2142 CurrentEntry
= RemoveHeadList(&pti
->PostedMessagesListHead
);
2143 CurrentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_MESSAGE
,
2145 MsqDestroyMessage(CurrentMessage
);
2148 /* remove the messages that have not yet been dispatched */
2149 while (!IsListEmpty(&pti
->SentMessagesListHead
))
2151 CurrentEntry
= RemoveHeadList(&pti
->SentMessagesListHead
);
2152 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
2155 TRACE("Notify the sender and remove a message from the queue that had not been dispatched\n");
2156 /* Only if the message has a sender was the message in the DispatchingList */
2157 if ((CurrentSentMessage
->ptiSender
)
2158 && (CurrentSentMessage
->DispatchingListEntry
.Flink
!= NULL
))
2160 RemoveEntryList(&CurrentSentMessage
->DispatchingListEntry
);
2163 /* wake the sender's thread */
2164 if (CurrentSentMessage
->CompletionEvent
!= NULL
)
2166 KeSetEvent(CurrentSentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
2169 if (CurrentSentMessage
->HasPackedLParam
)
2171 if (CurrentSentMessage
->Msg
.lParam
)
2172 ExFreePool((PVOID
)CurrentSentMessage
->Msg
.lParam
);
2175 /* free the message */
2176 ExFreePool(CurrentSentMessage
);
2179 /* notify senders of dispatching messages. This needs to be cleaned up if e.g.
2180 ExitThread() was called in a SendMessage() umode callback */
2181 while (!IsListEmpty(&pti
->LocalDispatchingMessagesHead
))
2183 CurrentEntry
= RemoveHeadList(&pti
->LocalDispatchingMessagesHead
);
2184 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
2187 /* remove the message from the dispatching list */
2188 if(CurrentSentMessage
->DispatchingListEntry
.Flink
!= NULL
)
2190 RemoveEntryList(&CurrentSentMessage
->DispatchingListEntry
);
2193 TRACE("Notify the sender, the thread has been terminated while dispatching a message!\n");
2195 /* wake the sender's thread */
2196 if (CurrentSentMessage
->CompletionEvent
!= NULL
)
2198 KeSetEvent(CurrentSentMessage
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
2201 if (CurrentSentMessage
->HasPackedLParam
)
2203 if (CurrentSentMessage
->Msg
.lParam
)
2204 ExFreePool((PVOID
)CurrentSentMessage
->Msg
.lParam
);
2207 /* free the message */
2208 ExFreePool(CurrentSentMessage
);
2211 /* tell other threads not to bother returning any info to us */
2212 while (! IsListEmpty(&pti
->DispatchingMessagesHead
))
2214 CurrentEntry
= RemoveHeadList(&pti
->DispatchingMessagesHead
);
2215 CurrentSentMessage
= CONTAINING_RECORD(CurrentEntry
, USER_SENT_MESSAGE
,
2216 DispatchingListEntry
);
2217 CurrentSentMessage
->CompletionEvent
= NULL
;
2218 CurrentSentMessage
->Result
= NULL
;
2220 /* do NOT dereference our message queue as it might get attempted to be
2224 // Clear it all out.
2227 pti
->pcti
->fsWakeBits
= 0;
2228 pti
->pcti
->fsChangeBits
= 0;
2231 pti
->nCntsQBits
[QSRosKey
] = 0;
2232 pti
->nCntsQBits
[QSRosMouseMove
] = 0;
2233 pti
->nCntsQBits
[QSRosMouseButton
] = 0;
2234 pti
->nCntsQBits
[QSRosPostMessage
] = 0;
2235 pti
->nCntsQBits
[QSRosSendMessage
] = 0;
2236 pti
->nCntsQBits
[QSRosHotKey
] = 0;
2237 pti
->nCntsQBits
[QSRosEvent
] = 0;
2241 MsqCleanupMessageQueue(PTHREADINFO pti
)
2243 PUSER_MESSAGE_QUEUE MessageQueue
;
2245 MessageQueue
= pti
->MessageQueue
;
2246 MessageQueue
->cThreads
--;
2248 if (MessageQueue
->cThreads
)
2250 if (MessageQueue
->ptiSysLock
== pti
) MessageQueue
->ptiSysLock
= NULL
;
2253 if (MessageQueue
->CursorObject
)
2255 PCURICON_OBJECT pCursor
= MessageQueue
->CursorObject
;
2257 /* Change to another cursor if we going to dereference current one
2258 Note: we can't use UserSetCursor because it uses current thread
2259 message queue instead of queue given for cleanup */
2260 if (IntGetSysCursorInfo()->CurrentCursorObject
== pCursor
)
2264 /* Get the screen DC */
2265 hdcScreen
= IntGetScreenDC();
2267 GreMovePointer(hdcScreen
, -1, -1);
2268 IntGetSysCursorInfo()->CurrentCursorObject
= NULL
;
2271 TRACE("DereferenceObject pCursor\n");
2272 UserDereferenceObject(pCursor
);
2275 if (gpqForeground
== MessageQueue
)
2277 IntSetFocusMessageQueue(NULL
);
2279 if (gpqForegroundPrev
== MessageQueue
)
2281 gpqForegroundPrev
= NULL
;
2283 if (gpqCursor
== MessageQueue
)
2289 PUSER_MESSAGE_QUEUE FASTCALL
2290 MsqCreateMessageQueue(PTHREADINFO pti
)
2292 PUSER_MESSAGE_QUEUE MessageQueue
;
2294 MessageQueue
= (PUSER_MESSAGE_QUEUE
)ExAllocatePoolWithTag(NonPagedPool
,
2295 sizeof(USER_MESSAGE_QUEUE
) + sizeof(THRDCARETINFO
),
2303 RtlZeroMemory(MessageQueue
, sizeof(USER_MESSAGE_QUEUE
) + sizeof(THRDCARETINFO
));
2304 /* hold at least one reference until it'll be destroyed */
2305 IntReferenceMessageQueue(MessageQueue
);
2306 /* initialize the queue */
2307 if (!MsqInitializeMessageQueue(pti
, MessageQueue
))
2309 IntDereferenceMessageQueue(MessageQueue
);
2313 return MessageQueue
;
2317 MsqDestroyMessageQueue(PTHREADINFO pti
)
2320 PUSER_MESSAGE_QUEUE MessageQueue
= pti
->MessageQueue
;
2322 MessageQueue
->QF_flags
|= QF_INDESTROY
;
2324 /* remove the message queue from any desktops */
2325 if ((desk
= InterlockedExchangePointer((PVOID
*)&MessageQueue
->Desktop
, 0)))
2327 (void)InterlockedExchangePointer((PVOID
*)&desk
->ActiveMessageQueue
, 0);
2328 IntDereferenceMessageQueue(MessageQueue
);
2332 MsqCleanupMessageQueue(pti
);
2334 /* decrease the reference counter, if it hits zero, the queue will be freed */
2335 IntDereferenceMessageQueue(MessageQueue
);
2339 MsqSetMessageExtraInfo(LPARAM lParam
)
2343 PUSER_MESSAGE_QUEUE MessageQueue
;
2345 pti
= PsGetCurrentThreadWin32Thread();
2346 MessageQueue
= pti
->MessageQueue
;
2352 Ret
= MessageQueue
->ExtraInfo
;
2353 MessageQueue
->ExtraInfo
= lParam
;
2359 MsqGetMessageExtraInfo(VOID
)
2362 PUSER_MESSAGE_QUEUE MessageQueue
;
2364 pti
= PsGetCurrentThreadWin32Thread();
2365 MessageQueue
= pti
->MessageQueue
;
2371 return MessageQueue
->ExtraInfo
;
2374 // ReplyMessage is called by the thread receiving the window message.
2376 co_MsqReplyMessage( LRESULT lResult
)
2378 PUSER_SENT_MESSAGE Message
;
2381 pti
= PsGetCurrentThreadWin32Thread();
2382 Message
= pti
->pusmCurrent
;
2384 if (!Message
) return FALSE
;
2386 if (Message
->QS_Flags
& QS_SMRESULT
) return FALSE
;
2388 // SendMessageXxx || Callback msg and not a notify msg
2389 if (Message
->ptiSender
|| Message
->CompletionCallback
)
2391 Message
->lResult
= lResult
;
2392 Message
->QS_Flags
|= QS_SMRESULT
;
2393 // See co_MsqDispatchOneSentMessage, change bits already accounted for and cleared and this msg is going away..
2399 MsqSetStateWindow(PTHREADINFO pti
, ULONG Type
, HWND hWnd
)
2402 PUSER_MESSAGE_QUEUE MessageQueue
;
2404 MessageQueue
= pti
->MessageQueue
;
2408 case MSQ_STATE_CAPTURE
:
2409 Prev
= MessageQueue
->spwndCapture
? UserHMGetHandle(MessageQueue
->spwndCapture
) : 0;
2410 MessageQueue
->spwndCapture
= ValidateHwndNoErr(hWnd
);
2412 case MSQ_STATE_ACTIVE
:
2413 Prev
= MessageQueue
->spwndActive
? UserHMGetHandle(MessageQueue
->spwndActive
) : 0;
2414 MessageQueue
->spwndActive
= ValidateHwndNoErr(hWnd
);
2416 case MSQ_STATE_FOCUS
:
2417 Prev
= MessageQueue
->spwndFocus
? UserHMGetHandle(MessageQueue
->spwndFocus
) : 0;
2418 MessageQueue
->spwndFocus
= ValidateHwndNoErr(hWnd
);
2420 case MSQ_STATE_MENUOWNER
:
2421 Prev
= MessageQueue
->MenuOwner
;
2422 MessageQueue
->MenuOwner
= hWnd
;
2424 case MSQ_STATE_MOVESIZE
:
2425 Prev
= MessageQueue
->MoveSize
;
2426 MessageQueue
->MoveSize
= hWnd
;
2428 case MSQ_STATE_CARET
:
2429 ASSERT(MessageQueue
->CaretInfo
);
2430 Prev
= MessageQueue
->CaretInfo
->hWnd
;
2431 MessageQueue
->CaretInfo
->hWnd
= hWnd
;
2440 NtUserGetKeyState(INT key
)
2446 Ret
= UserGetKeyState(key
);
2456 NtUserGetKeyboardState(LPBYTE lpKeyState
)
2458 DWORD i
, ret
= TRUE
;
2460 PUSER_MESSAGE_QUEUE MessageQueue
;
2464 pti
= PsGetCurrentThreadWin32Thread();
2465 MessageQueue
= pti
->MessageQueue
;
2469 /* Probe and copy key state to an array */
2470 ProbeForWrite(lpKeyState
, 256 * sizeof(BYTE
), 1);
2471 for (i
= 0; i
< 256; ++i
)
2474 if (IS_KEY_DOWN(MessageQueue
->afKeyState
, i
))
2475 lpKeyState
[i
] |= KS_DOWN_BIT
;
2476 if (IS_KEY_LOCKED(MessageQueue
->afKeyState
, i
))
2477 lpKeyState
[i
] |= KS_LOCK_BIT
;
2480 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2482 SetLastNtError(_SEH2_GetExceptionCode());
2494 NtUserSetKeyboardState(LPBYTE pKeyState
)
2499 PUSER_MESSAGE_QUEUE MessageQueue
;
2501 UserEnterExclusive();
2503 pti
= PsGetCurrentThreadWin32Thread();
2504 MessageQueue
= pti
->MessageQueue
;
2508 ProbeForRead(pKeyState
, 256 * sizeof(BYTE
), 1);
2509 for (i
= 0; i
< 256; ++i
)
2511 SET_KEY_DOWN(MessageQueue
->afKeyState
, i
, pKeyState
[i
] & KS_DOWN_BIT
);
2512 SET_KEY_LOCKED(MessageQueue
->afKeyState
, i
, pKeyState
[i
] & KS_LOCK_BIT
);
2515 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2517 SetLastNtError(_SEH2_GetExceptionCode());