[Win32SS]
[reactos.git] / reactos / win32ss / user / ntuser / msgqueue.c
1 /*
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)
7 Alexandre Julliard
8 Maarten Lankhorst
9 */
10
11 #include <win32k.h>
12 DBG_DEFAULT_CHANNEL(UserMsgQ);
13
14 /* GLOBALS *******************************************************************/
15
16 static PPAGED_LOOKASIDE_LIST pgMessageLookasideList;
17 static PPAGED_LOOKASIDE_LIST pgSendMsgLookasideList;
18 INT SendMsgCount = 0;
19 PUSER_MESSAGE_QUEUE gpqCursor;
20 ULONG_PTR gdwMouseMoveExtraInfo = 0;
21 DWORD gdwMouseMoveTimeStamp = 0;
22 LIST_ENTRY usmList;
23
24 /* FUNCTIONS *****************************************************************/
25
26 INIT_FUNCTION
27 NTSTATUS
28 NTAPI
29 MsqInitializeImpl(VOID)
30 {
31 // Setup Post Messages
32 pgMessageLookasideList = ExAllocatePoolWithTag(NonPagedPool, sizeof(PAGED_LOOKASIDE_LIST), TAG_USRMSG);
33 if (!pgMessageLookasideList)
34 return STATUS_NO_MEMORY;
35 ExInitializePagedLookasideList(pgMessageLookasideList,
36 NULL,
37 NULL,
38 0,
39 sizeof(USER_MESSAGE),
40 TAG_USRMSG,
41 256);
42 // Setup Send Messages
43 pgSendMsgLookasideList = ExAllocatePoolWithTag(NonPagedPool, sizeof(PAGED_LOOKASIDE_LIST), TAG_USRMSG);
44 if (!pgSendMsgLookasideList)
45 return STATUS_NO_MEMORY;
46 ExInitializePagedLookasideList(pgSendMsgLookasideList,
47 NULL,
48 NULL,
49 0,
50 sizeof(USER_SENT_MESSAGE),
51 TAG_USRMSG,
52 16);
53
54 InitializeListHead(&usmList);
55
56 return(STATUS_SUCCESS);
57 }
58
59 PWND FASTCALL
60 IntTopLevelWindowFromPoint(INT x, INT y)
61 {
62 PWND pWnd, pwndDesktop;
63
64 /* Get the desktop window */
65 pwndDesktop = UserGetDesktopWindow();
66 if (!pwndDesktop)
67 return NULL;
68
69 /* Loop all top level windows */
70 for (pWnd = pwndDesktop->spwndChild;
71 pWnd != NULL;
72 pWnd = pWnd->spwndNext)
73 {
74 if (pWnd->state2 & WNDS2_INDESTROY || pWnd->state & WNDS_DESTROYED)
75 {
76 TRACE("The Window is in DESTROY!\n");
77 continue;
78 }
79
80 if ((pWnd->style & WS_VISIBLE) &&
81 (pWnd->ExStyle & (WS_EX_LAYERED|WS_EX_TRANSPARENT)) != (WS_EX_LAYERED|WS_EX_TRANSPARENT) &&
82 IntPtInWindow(pWnd, x, y))
83 return pWnd;
84 }
85
86 /* Window has not been found */
87 return pwndDesktop;
88 }
89
90 PCURICON_OBJECT
91 FASTCALL
92 UserSetCursor(
93 PCURICON_OBJECT NewCursor,
94 BOOL ForceChange)
95 {
96 PCURICON_OBJECT OldCursor;
97 HDC hdcScreen;
98 PTHREADINFO pti;
99 PUSER_MESSAGE_QUEUE MessageQueue;
100 PWND pWnd;
101
102 pti = PsGetCurrentThreadWin32Thread();
103 MessageQueue = pti->MessageQueue;
104
105 OldCursor = MessageQueue->CursorObject;
106
107 /* Check if cursors are different */
108 if (OldCursor == NewCursor)
109 return OldCursor;
110
111 /* Update cursor for this message queue */
112 MessageQueue->CursorObject = NewCursor;
113
114 /* If cursor is not visible we have nothing to do */
115 if (MessageQueue->iCursorLevel < 0)
116 return OldCursor;
117
118 // Fixes the error message "Not the same cursor!".
119 if (gpqCursor == NULL)
120 {
121 gpqCursor = MessageQueue;
122 }
123
124 /* Update cursor if this message queue controls it */
125 pWnd = IntTopLevelWindowFromPoint(gpsi->ptCursor.x, gpsi->ptCursor.y);
126 if (pWnd && pWnd->head.pti->MessageQueue == MessageQueue)
127 {
128 /* Get the screen DC */
129 if (!(hdcScreen = IntGetScreenDC()))
130 {
131 return NULL;
132 }
133
134 if (NewCursor)
135 {
136 /* Call GDI to set the new screen cursor */
137 PCURICON_OBJECT CursorFrame = NewCursor;
138 if(NewCursor->CURSORF_flags & CURSORF_ACON)
139 {
140 FIXME("Should animate the cursor, using only the first frame now.\n");
141 CursorFrame = ((PACON)NewCursor)->aspcur[0];
142 }
143 GreSetPointerShape(hdcScreen,
144 CursorFrame->hbmAlpha ? NULL : NewCursor->hbmMask,
145 CursorFrame->hbmAlpha ? NewCursor->hbmAlpha : NewCursor->hbmColor,
146 CursorFrame->xHotspot,
147 CursorFrame->yHotspot,
148 gpsi->ptCursor.x,
149 gpsi->ptCursor.y,
150 CursorFrame->hbmAlpha ? SPS_ALPHA : 0);
151 }
152 else /* Note: OldCursor != NewCursor so we have to hide cursor */
153 {
154 /* Remove the cursor */
155 GreMovePointer(hdcScreen, -1, -1);
156 TRACE("Removing pointer!\n");
157 }
158 IntGetSysCursorInfo()->CurrentCursorObject = NewCursor;
159 }
160
161 /* Return the old cursor */
162 return OldCursor;
163 }
164
165 /* Called from NtUserCallOneParam with Routine ONEPARAM_ROUTINE_SHOWCURSOR
166 * User32 macro NtUserShowCursor */
167 int UserShowCursor(BOOL bShow)
168 {
169 HDC hdcScreen;
170 PTHREADINFO pti;
171 PUSER_MESSAGE_QUEUE MessageQueue;
172 PWND pWnd;
173
174 if (!(hdcScreen = IntGetScreenDC()))
175 {
176 return -1; /* No mouse */
177 }
178
179 pti = PsGetCurrentThreadWin32Thread();
180 MessageQueue = pti->MessageQueue;
181
182 /* Update counter */
183 MessageQueue->iCursorLevel += bShow ? 1 : -1;
184 pti->iCursorLevel += bShow ? 1 : -1;
185
186 /* Check for trivial cases */
187 if ((bShow && MessageQueue->iCursorLevel != 0) ||
188 (!bShow && MessageQueue->iCursorLevel != -1))
189 {
190 /* Note: w don't update global info here because it is used only
191 internally to check if cursor is visible */
192 return MessageQueue->iCursorLevel;
193 }
194
195 /* Check if cursor is above window owned by this MessageQueue */
196 pWnd = IntTopLevelWindowFromPoint(gpsi->ptCursor.x, gpsi->ptCursor.y);
197 if (pWnd && pWnd->head.pti->MessageQueue == MessageQueue)
198 {
199 if (bShow)
200 {
201 /* Show the pointer */
202 GreMovePointer(hdcScreen, gpsi->ptCursor.x, gpsi->ptCursor.y);
203 TRACE("Showing pointer!\n");
204 }
205 else
206 {
207 /* Remove the pointer */
208 GreMovePointer(hdcScreen, -1, -1);
209 TRACE("Removing pointer!\n");
210 }
211
212 /* Update global info */
213 IntGetSysCursorInfo()->ShowingCursor = MessageQueue->iCursorLevel;
214 }
215
216 return MessageQueue->iCursorLevel;
217 }
218
219 DWORD FASTCALL
220 UserGetKeyState(DWORD dwKey)
221 {
222 DWORD dwRet = 0;
223 PTHREADINFO pti;
224 PUSER_MESSAGE_QUEUE MessageQueue;
225
226 pti = PsGetCurrentThreadWin32Thread();
227 MessageQueue = pti->MessageQueue;
228
229 if (dwKey < 0x100)
230 {
231 if (IS_KEY_DOWN(MessageQueue->afKeyState, dwKey))
232 dwRet |= 0xFF80; // If down, windows returns 0xFF80.
233 if (IS_KEY_LOCKED(MessageQueue->afKeyState, dwKey))
234 dwRet |= 0x1;
235 }
236 else
237 {
238 EngSetLastError(ERROR_INVALID_PARAMETER);
239 }
240 return dwRet;
241 }
242
243 /* change the input key state for a given key */
244 static VOID
245 UpdateKeyState(PUSER_MESSAGE_QUEUE MessageQueue, WORD wVk, BOOL bIsDown)
246 {
247 TRACE("UpdateKeyState wVk: %u, bIsDown: %d\n", wVk, bIsDown);
248
249 if (bIsDown)
250 {
251 /* If it's first key down event, xor lock bit */
252 if (!IS_KEY_DOWN(MessageQueue->afKeyState, wVk))
253 SET_KEY_LOCKED(MessageQueue->afKeyState, wVk, !IS_KEY_LOCKED(MessageQueue->afKeyState, wVk));
254
255 SET_KEY_DOWN(MessageQueue->afKeyState, wVk, TRUE);
256 MessageQueue->afKeyRecentDown[wVk / 8] |= (1 << (wVk % 8));
257 }
258 else
259 SET_KEY_DOWN(MessageQueue->afKeyState, wVk, FALSE);
260 }
261
262 /* update the input key state for a keyboard message */
263 static VOID
264 UpdateKeyStateFromMsg(PUSER_MESSAGE_QUEUE MessageQueue, MSG* msg)
265 {
266 UCHAR key;
267 BOOL down = FALSE;
268
269 TRACE("UpdateKeyStateFromMsg message:%u\n", msg->message);
270
271 switch (msg->message)
272 {
273 case WM_LBUTTONDOWN:
274 down = TRUE;
275 /* fall through */
276 case WM_LBUTTONUP:
277 UpdateKeyState(MessageQueue, VK_LBUTTON, down);
278 break;
279 case WM_MBUTTONDOWN:
280 down = TRUE;
281 /* fall through */
282 case WM_MBUTTONUP:
283 UpdateKeyState(MessageQueue, VK_MBUTTON, down);
284 break;
285 case WM_RBUTTONDOWN:
286 down = TRUE;
287 /* fall through */
288 case WM_RBUTTONUP:
289 UpdateKeyState(MessageQueue, VK_RBUTTON, down);
290 break;
291 case WM_XBUTTONDOWN:
292 down = TRUE;
293 /* fall through */
294 case WM_XBUTTONUP:
295 if (msg->wParam == XBUTTON1)
296 UpdateKeyState(MessageQueue, VK_XBUTTON1, down);
297 else if (msg->wParam == XBUTTON2)
298 UpdateKeyState(MessageQueue, VK_XBUTTON2, down);
299 break;
300 case WM_KEYDOWN:
301 case WM_SYSKEYDOWN:
302 down = TRUE;
303 /* fall through */
304 case WM_KEYUP:
305 case WM_SYSKEYUP:
306 key = (UCHAR)msg->wParam;
307 UpdateKeyState(MessageQueue, key, down);
308 switch(key)
309 {
310 case VK_LCONTROL:
311 case VK_RCONTROL:
312 down = IS_KEY_DOWN(MessageQueue->afKeyState, VK_LCONTROL) || IS_KEY_DOWN(MessageQueue->afKeyState, VK_RCONTROL);
313 UpdateKeyState(MessageQueue, VK_CONTROL, down);
314 break;
315 case VK_LMENU:
316 case VK_RMENU:
317 down = IS_KEY_DOWN(MessageQueue->afKeyState, VK_LMENU) || IS_KEY_DOWN(MessageQueue->afKeyState, VK_RMENU);
318 UpdateKeyState(MessageQueue, VK_MENU, down);
319 break;
320 case VK_LSHIFT:
321 case VK_RSHIFT:
322 down = IS_KEY_DOWN(MessageQueue->afKeyState, VK_LSHIFT) || IS_KEY_DOWN(MessageQueue->afKeyState, VK_RSHIFT);
323 UpdateKeyState(MessageQueue, VK_SHIFT, down);
324 break;
325 }
326 break;
327 }
328 }
329
330 /*
331 Get down key states from the queue of prior processed input message key states.
332
333 This fixes the left button dragging on the desktop and release sticking outline issue.
334 USB Tablet pointer seems to stick the most and leaves the box outline displayed.
335 */
336 WPARAM FASTCALL
337 MsqGetDownKeyState(PUSER_MESSAGE_QUEUE MessageQueue)
338 {
339 WPARAM ret = 0;
340
341 if (gspv.bMouseBtnSwap)
342 {
343 if (IS_KEY_DOWN(MessageQueue->afKeyState, VK_RBUTTON)) ret |= MK_LBUTTON;
344 if (IS_KEY_DOWN(MessageQueue->afKeyState, VK_LBUTTON)) ret |= MK_RBUTTON;
345 }
346 else
347 {
348 if (IS_KEY_DOWN(MessageQueue->afKeyState, VK_LBUTTON)) ret |= MK_LBUTTON;
349 if (IS_KEY_DOWN(MessageQueue->afKeyState, VK_RBUTTON)) ret |= MK_RBUTTON;
350 }
351
352 if (IS_KEY_DOWN(MessageQueue->afKeyState, VK_MBUTTON)) ret |= MK_MBUTTON;
353 if (IS_KEY_DOWN(MessageQueue->afKeyState, VK_SHIFT)) ret |= MK_SHIFT;
354 if (IS_KEY_DOWN(MessageQueue->afKeyState, VK_CONTROL)) ret |= MK_CONTROL;
355 if (IS_KEY_DOWN(MessageQueue->afKeyState, VK_XBUTTON1)) ret |= MK_XBUTTON1;
356 if (IS_KEY_DOWN(MessageQueue->afKeyState, VK_XBUTTON2)) ret |= MK_XBUTTON2;
357 return ret;
358 }
359
360 HANDLE FASTCALL
361 IntMsqSetWakeMask(DWORD WakeMask)
362 {
363 PTHREADINFO Win32Thread;
364 HANDLE MessageEventHandle;
365 DWORD dwFlags = HIWORD(WakeMask);
366
367 Win32Thread = PsGetCurrentThreadWin32Thread();
368 if (Win32Thread == NULL || Win32Thread->MessageQueue == NULL)
369 return 0;
370
371 // Win32Thread->pEventQueueServer; IntMsqSetWakeMask returns Win32Thread->hEventQueueClient
372 MessageEventHandle = Win32Thread->hEventQueueClient;
373
374 if (Win32Thread->pcti)
375 {
376 if ( (Win32Thread->pcti->fsChangeBits & LOWORD(WakeMask)) ||
377 ( (dwFlags & MWMO_INPUTAVAILABLE) && (Win32Thread->pcti->fsWakeBits & LOWORD(WakeMask)) ) )
378 {
379 ERR("Chg 0x%x Wake 0x%x Mask 0x%x\n",Win32Thread->pcti->fsChangeBits, Win32Thread->pcti->fsWakeBits, WakeMask);
380 KeSetEvent(Win32Thread->pEventQueueServer, IO_NO_INCREMENT, FALSE); // Wake it up!
381 return MessageEventHandle;
382 }
383 }
384
385 IdlePing();
386
387 return MessageEventHandle;
388 }
389
390 BOOL FASTCALL
391 IntMsqClearWakeMask(VOID)
392 {
393 PTHREADINFO Win32Thread;
394
395 Win32Thread = PsGetCurrentThreadWin32Thread();
396 if (Win32Thread == NULL || Win32Thread->MessageQueue == NULL)
397 return FALSE;
398 // Very hacky, but that is what they do.
399 Win32Thread->pcti->fsWakeBits = 0;
400
401 IdlePong();
402
403 return TRUE;
404 }
405
406 /*
407 Due to the uncertainty of knowing what was set in our multilevel message queue,
408 and even if the bits are all cleared. The same as cTimers/cPaintsReady.
409 I think this is the best solution... (jt) */
410 VOID FASTCALL
411 MsqWakeQueue(PTHREADINFO pti, DWORD MessageBits, BOOL KeyEvent)
412 {
413 PUSER_MESSAGE_QUEUE Queue;
414
415 Queue = pti->MessageQueue;
416
417 if (Queue->QF_flags & QF_INDESTROY)
418 {
419 ERR("This Message Queue is in Destroy!\n");
420 }
421 pti->pcti->fsWakeBits |= MessageBits;
422 pti->pcti->fsChangeBits |= MessageBits;
423
424 // Start bit accounting to help clear the main set of bits.
425 if (MessageBits & QS_KEY)
426 {
427 pti->nCntsQBits[QSRosKey]++;
428 }
429 if (MessageBits & QS_MOUSE)
430 {
431 if (MessageBits & QS_MOUSEMOVE) pti->nCntsQBits[QSRosMouseMove]++;
432 if (MessageBits & QS_MOUSEBUTTON) pti->nCntsQBits[QSRosMouseButton]++;
433 }
434 if (MessageBits & QS_POSTMESSAGE) pti->nCntsQBits[QSRosPostMessage]++;
435 if (MessageBits & QS_SENDMESSAGE) pti->nCntsQBits[QSRosSendMessage]++;
436 if (MessageBits & QS_HOTKEY) pti->nCntsQBits[QSRosHotKey]++;
437 if (MessageBits & QS_EVENT) pti->nCntsQBits[QSRosEvent]++;
438
439 if (KeyEvent)
440 KeSetEvent(pti->pEventQueueServer, IO_NO_INCREMENT, FALSE);
441 }
442
443 VOID FASTCALL
444 ClearMsgBitsMask(PTHREADINFO pti, UINT MessageBits)
445 {
446 UINT ClrMask = 0;
447
448 if (MessageBits & QS_KEY)
449 {
450 if (--pti->nCntsQBits[QSRosKey] == 0) ClrMask |= QS_KEY;
451 }
452 if (MessageBits & QS_MOUSEMOVE)
453 { // Account for tracking mouse moves..
454 if (pti->nCntsQBits[QSRosMouseMove])
455 {
456 pti->nCntsQBits[QSRosMouseMove] = 0; // Throttle down count. Up to > 3:1 entries are ignored.
457 ClrMask |= QS_MOUSEMOVE;
458 }
459 }
460 if (MessageBits & QS_MOUSEBUTTON)
461 {
462 if (--pti->nCntsQBits[QSRosMouseButton] == 0) ClrMask |= QS_MOUSEBUTTON;
463 }
464 if (MessageBits & QS_POSTMESSAGE)
465 {
466 if (--pti->nCntsQBits[QSRosPostMessage] == 0) ClrMask |= QS_POSTMESSAGE;
467 }
468 if (MessageBits & QS_TIMER) // ReactOS hard coded.
469 { // Handle timer bits here.
470 if ( pti->cTimersReady )
471 {
472 if (--pti->cTimersReady == 0) ClrMask |= QS_TIMER;
473 }
474 }
475 if (MessageBits & QS_PAINT) // ReactOS hard coded.
476 { // Handle paint bits here.
477 if ( pti->cPaintsReady )
478 {
479 if (--pti->cPaintsReady == 0) ClrMask |= QS_PAINT;
480 }
481 }
482 if (MessageBits & QS_SENDMESSAGE)
483 {
484 if (--pti->nCntsQBits[QSRosSendMessage] == 0) ClrMask |= QS_SENDMESSAGE;
485 }
486 if (MessageBits & QS_HOTKEY)
487 {
488 if (--pti->nCntsQBits[QSRosHotKey] == 0) ClrMask |= QS_HOTKEY;
489 }
490 if (MessageBits & QS_EVENT)
491 {
492 if (--pti->nCntsQBits[QSRosEvent] == 0) ClrMask |= QS_EVENT;
493 }
494
495 pti->pcti->fsWakeBits &= ~ClrMask;
496 pti->pcti->fsChangeBits &= ~ClrMask;
497 }
498
499 VOID FASTCALL
500 MsqIncPaintCountQueue(PTHREADINFO pti)
501 {
502 pti->cPaintsReady++;
503 MsqWakeQueue(pti, QS_PAINT, TRUE);
504 }
505
506 VOID FASTCALL
507 MsqDecPaintCountQueue(PTHREADINFO pti)
508 {
509 ClearMsgBitsMask(pti, QS_PAINT);
510 }
511
512 /*
513 Post the move or update the message still pending to be processed.
514 Do not overload the queue with mouse move messages.
515 */
516 VOID FASTCALL
517 MsqPostMouseMove(PTHREADINFO pti, MSG* Msg, LONG_PTR ExtraInfo)
518 {
519 PUSER_MESSAGE Message;
520 PLIST_ENTRY ListHead;
521 PUSER_MESSAGE_QUEUE MessageQueue = pti->MessageQueue;
522
523 ListHead = &MessageQueue->HardwareMessagesListHead;
524
525 // Do nothing if empty.
526 if (!IsListEmpty(ListHead->Flink))
527 {
528 // Look at the end of the list,
529 Message = CONTAINING_RECORD(ListHead->Blink, USER_MESSAGE, ListEntry);
530
531 // If the mouse move message is existing on the list,
532 if (Message->Msg.message == WM_MOUSEMOVE)
533 {
534 // Overwrite the message with updated data!
535 Message->Msg = *Msg;
536
537 MsqWakeQueue(pti, QS_MOUSEMOVE, TRUE);
538 return;
539 }
540 }
541
542 MsqPostMessage(pti, Msg, TRUE, QS_MOUSEMOVE, 0, ExtraInfo);
543 }
544
545 /*
546 Bring together the mouse move message.
547 Named "Coalesce" from Amine email ;^) (jt).
548 */
549 VOID FASTCALL
550 IntCoalesceMouseMove(PTHREADINFO pti)
551 {
552 MSG Msg;
553 LARGE_INTEGER LargeTickCount;
554
555 // Force time stamp to update, keeping message time in sync.
556 if (gdwMouseMoveTimeStamp == 0)
557 {
558 KeQueryTickCount(&LargeTickCount);
559 gdwMouseMoveTimeStamp = MsqCalculateMessageTime(&LargeTickCount);
560 }
561
562 // Build mouse move message.
563 Msg.hwnd = NULL;
564 Msg.message = WM_MOUSEMOVE;
565 Msg.wParam = 0;
566 Msg.lParam = MAKELONG(gpsi->ptCursor.x, gpsi->ptCursor.y);
567 Msg.time = gdwMouseMoveTimeStamp;
568 Msg.pt = gpsi->ptCursor;
569
570 // Post the move.
571 MsqPostMouseMove(pti, &Msg, gdwMouseMoveExtraInfo);
572
573 // Zero the time stamp.
574 gdwMouseMoveTimeStamp = 0;
575
576 // Clear flag since the move was posted.
577 pti->MessageQueue->QF_flags &= ~QF_MOUSEMOVED;
578 }
579
580 VOID FASTCALL
581 co_MsqInsertMouseMessage(MSG* Msg, DWORD flags, ULONG_PTR dwExtraInfo, BOOL Hook)
582 {
583 LARGE_INTEGER LargeTickCount;
584 MSLLHOOKSTRUCT MouseHookData;
585 // PDESKTOP pDesk;
586 PWND pwnd, pwndDesktop;
587 HDC hdcScreen;
588 PTHREADINFO pti;
589 PUSER_MESSAGE_QUEUE MessageQueue;
590 PSYSTEM_CURSORINFO CurInfo;
591
592 KeQueryTickCount(&LargeTickCount);
593 Msg->time = MsqCalculateMessageTime(&LargeTickCount);
594
595 MouseHookData.pt.x = LOWORD(Msg->lParam);
596 MouseHookData.pt.y = HIWORD(Msg->lParam);
597 switch (Msg->message)
598 {
599 case WM_MOUSEWHEEL:
600 MouseHookData.mouseData = MAKELONG(0, GET_WHEEL_DELTA_WPARAM(Msg->wParam));
601 break;
602 case WM_XBUTTONDOWN:
603 case WM_XBUTTONUP:
604 case WM_XBUTTONDBLCLK:
605 case WM_NCXBUTTONDOWN:
606 case WM_NCXBUTTONUP:
607 case WM_NCXBUTTONDBLCLK:
608 MouseHookData.mouseData = MAKELONG(0, HIWORD(Msg->wParam));
609 break;
610 default:
611 MouseHookData.mouseData = 0;
612 break;
613 }
614
615 MouseHookData.flags = flags; // LLMHF_INJECTED
616 MouseHookData.time = Msg->time;
617 MouseHookData.dwExtraInfo = dwExtraInfo;
618
619 /* If the hook procedure returned non zero, dont send the message */
620 if (Hook)
621 {
622 if (co_HOOK_CallHooks(WH_MOUSE_LL, HC_ACTION, Msg->message, (LPARAM) &MouseHookData))
623 return;
624 }
625
626 /* Get the desktop window */
627 pwndDesktop = UserGetDesktopWindow();
628 if (!pwndDesktop) return;
629 // pDesk = pwndDesktop->head.rpdesk;
630
631 /* Check if the mouse is captured */
632 Msg->hwnd = IntGetCaptureWindow();
633 if (Msg->hwnd != NULL)
634 {
635 pwnd = UserGetWindowObject(Msg->hwnd);
636 }
637 else
638 {
639 pwnd = IntTopLevelWindowFromPoint(Msg->pt.x, Msg->pt.y);
640 if (pwnd) Msg->hwnd = pwnd->head.h;
641 }
642
643 hdcScreen = IntGetScreenDC();
644 CurInfo = IntGetSysCursorInfo();
645
646 /* Check if we found a window */
647 if (Msg->hwnd != NULL && pwnd != NULL)
648 {
649 pti = pwnd->head.pti;
650 MessageQueue = pti->MessageQueue;
651
652 if (MessageQueue->QF_flags & QF_INDESTROY)
653 {
654 ERR("Mouse is over a Window with a Dead Message Queue!\n");
655 return;
656 }
657
658 // Check to see if this is attached.
659 if ( pti != MessageQueue->ptiMouse &&
660 MessageQueue->cThreads > 1 )
661 {
662 // Set the send pti to the message queue mouse pti.
663 pti = MessageQueue->ptiMouse;
664 }
665
666 if (Msg->message == WM_MOUSEMOVE)
667 {
668 /* Check if cursor should be visible */
669 if(hdcScreen &&
670 MessageQueue->CursorObject &&
671 MessageQueue->iCursorLevel >= 0)
672 {
673 /* Check if shape has changed */
674 if(CurInfo->CurrentCursorObject != MessageQueue->CursorObject)
675 {
676 /* Call GDI to set the new screen cursor */
677 GreSetPointerShape(hdcScreen,
678 MessageQueue->CursorObject->hbmAlpha ?
679 NULL : MessageQueue->CursorObject->hbmMask,
680 MessageQueue->CursorObject->hbmAlpha ?
681 MessageQueue->CursorObject->hbmAlpha : MessageQueue->CursorObject->hbmColor,
682 MessageQueue->CursorObject->xHotspot,
683 MessageQueue->CursorObject->yHotspot,
684 gpsi->ptCursor.x,
685 gpsi->ptCursor.y,
686 MessageQueue->CursorObject->hbmAlpha ? SPS_ALPHA : 0);
687
688 } else
689 GreMovePointer(hdcScreen, Msg->pt.x, Msg->pt.y);
690 }
691 /* Check if we have to hide cursor */
692 else if (CurInfo->ShowingCursor >= 0)
693 GreMovePointer(hdcScreen, -1, -1);
694
695 /* Update global cursor info */
696 CurInfo->ShowingCursor = MessageQueue->iCursorLevel;
697 CurInfo->CurrentCursorObject = MessageQueue->CursorObject;
698 gpqCursor = MessageQueue;
699
700 /* Mouse move is a special case */
701 MessageQueue->QF_flags |= QF_MOUSEMOVED;
702 gdwMouseMoveExtraInfo = dwExtraInfo;
703 gdwMouseMoveTimeStamp = Msg->time;
704 MsqWakeQueue(pti, QS_MOUSEMOVE, TRUE);
705 }
706 else
707 {
708 if (!IntGetCaptureWindow())
709 {
710 // ERR("ptiLastInput is set\n");
711 // ptiLastInput = pti; // Once this is set during Reboot or Shutdown, this prevents the exit window having foreground.
712 // Find all the Move Mouse calls and fix mouse set active focus issues......
713 }
714
715 // Post mouse move before posting mouse buttons, keep it in sync.
716 if (pti->MessageQueue->QF_flags & QF_MOUSEMOVED)
717 {
718 IntCoalesceMouseMove(pti);
719 }
720
721 TRACE("Posting mouse message to hwnd=%p!\n", UserHMGetHandle(pwnd));
722 MsqPostMessage(pti, Msg, TRUE, QS_MOUSEBUTTON, 0, dwExtraInfo);
723 }
724 }
725 else if (hdcScreen)
726 {
727 /* always show cursor on background; FIXME: set default pointer */
728 GreMovePointer(hdcScreen, Msg->pt.x, Msg->pt.y);
729 CurInfo->ShowingCursor = 0;
730 }
731 }
732
733 PUSER_MESSAGE FASTCALL
734 MsqCreateMessage(LPMSG Msg)
735 {
736 PUSER_MESSAGE Message;
737
738 Message = ExAllocateFromPagedLookasideList(pgMessageLookasideList);
739 if (!Message)
740 {
741 return NULL;
742 }
743
744 RtlZeroMemory(Message, sizeof(*Message));
745 RtlMoveMemory(&Message->Msg, Msg, sizeof(MSG));
746
747 return Message;
748 }
749
750 VOID FASTCALL
751 MsqDestroyMessage(PUSER_MESSAGE Message)
752 {
753 if (Message->pti == NULL)
754 {
755 ERR("Double Free Message\n");
756 return;
757 }
758 Message->pti = NULL;
759 ExFreeToPagedLookasideList(pgMessageLookasideList, Message);
760 }
761
762 PUSER_SENT_MESSAGE FASTCALL
763 AllocateUserMessage(BOOL KEvent)
764 {
765 PUSER_SENT_MESSAGE Message;
766
767 if(!(Message = ExAllocateFromPagedLookasideList(pgSendMsgLookasideList)))
768 {
769 ERR("AllocateUserMessage(): Not enough memory to allocate a message");
770 return NULL;
771 }
772 RtlZeroMemory(Message, sizeof(USER_SENT_MESSAGE));
773
774 if (KEvent)
775 {
776 Message->pkCompletionEvent = &Message->CompletionEvent;
777
778 KeInitializeEvent(Message->pkCompletionEvent, NotificationEvent, FALSE);
779 }
780 SendMsgCount++;
781 TRACE("AUM pti %p msg %p\n",PsGetCurrentThreadWin32Thread(),Message);
782 return Message;
783 }
784
785 VOID FASTCALL
786 FreeUserMessage(PUSER_SENT_MESSAGE Message)
787 {
788 Message->pkCompletionEvent = NULL;
789
790 /* Remove it from the list */
791 RemoveEntryList(&Message->ListEntry);
792
793 ExFreeToPagedLookasideList(pgSendMsgLookasideList, Message);
794 SendMsgCount--;
795 }
796
797 VOID APIENTRY
798 MsqRemoveWindowMessagesFromQueue(PWND Window)
799 {
800 PTHREADINFO pti;
801 PUSER_SENT_MESSAGE SentMessage;
802 PUSER_MESSAGE PostedMessage;
803 PLIST_ENTRY CurrentEntry, ListHead;
804
805 ASSERT(Window);
806
807 pti = Window->head.pti;
808
809 /* remove the posted messages for this window */
810 CurrentEntry = pti->PostedMessagesListHead.Flink;
811 ListHead = &pti->PostedMessagesListHead;
812 while (CurrentEntry != ListHead)
813 {
814 PostedMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE, ListEntry);
815
816 if (PostedMessage->Msg.hwnd == Window->head.h)
817 {
818 if (PostedMessage->Msg.message == WM_QUIT && pti->QuitPosted == 0)
819 {
820 pti->QuitPosted = 1;
821 pti->exitCode = PostedMessage->Msg.wParam;
822 }
823 RemoveEntryList(&PostedMessage->ListEntry);
824 ClearMsgBitsMask(pti, PostedMessage->QS_Flags);
825 MsqDestroyMessage(PostedMessage);
826 CurrentEntry = pti->PostedMessagesListHead.Flink;
827 }
828 else
829 {
830 CurrentEntry = CurrentEntry->Flink;
831 }
832 }
833
834 /* remove the sent messages for this window */
835 CurrentEntry = pti->SentMessagesListHead.Flink;
836 ListHead = &pti->SentMessagesListHead;
837 while (CurrentEntry != ListHead)
838 {
839 SentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE, ListEntry);
840
841 if(SentMessage->Msg.hwnd == Window->head.h)
842 {
843 ERR("Remove Window Messages %p From Sent Queue\n",SentMessage);
844 #if 0 // Should mark these as invalid and allow the rest clean up, so far no harm by just commenting out. See CORE-9210.
845 ClearMsgBitsMask(pti, SentMessage->QS_Flags);
846
847 /* wake the sender's thread */
848 if (SentMessage->pkCompletionEvent != NULL)
849 {
850 KeSetEvent(SentMessage->pkCompletionEvent, IO_NO_INCREMENT, FALSE);
851 }
852
853 if (SentMessage->HasPackedLParam)
854 {
855 if (SentMessage->Msg.lParam)
856 ExFreePool((PVOID)SentMessage->Msg.lParam);
857 }
858
859 /* free the message */
860 FreeUserMessage(SentMessage);
861
862 CurrentEntry = pti->SentMessagesListHead.Flink;
863 #endif
864 CurrentEntry = CurrentEntry->Flink;
865 }
866 else
867 {
868 CurrentEntry = CurrentEntry->Flink;
869 }
870 }
871 }
872
873 BOOLEAN FASTCALL
874 co_MsqDispatchOneSentMessage(
875 _In_ PTHREADINFO pti)
876 {
877 PUSER_SENT_MESSAGE SaveMsg, Message;
878 PLIST_ENTRY Entry;
879 BOOL Ret;
880 LRESULT Result = 0;
881
882 ASSERT(pti == PsGetCurrentThreadWin32Thread());
883
884 if (IsListEmpty(&pti->SentMessagesListHead))
885 {
886 return(FALSE);
887 }
888
889 /* remove it from the list of pending messages */
890 Entry = RemoveHeadList(&pti->SentMessagesListHead);
891 Message = CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry);
892
893 // Signal this message is being processed.
894 Message->flags |= SMF_RECEIVERBUSY|SMF_RECEIVEDMESSAGE;
895
896 SaveMsg = pti->pusmCurrent;
897 pti->pusmCurrent = Message;
898
899 // Processing a message sent to it from another thread.
900 if ( ( Message->ptiSender && pti != Message->ptiSender) ||
901 ( Message->ptiCallBackSender && pti != Message->ptiCallBackSender ))
902 { // most likely, but, to be sure.
903 pti->pcti->CTI_flags |= CTI_INSENDMESSAGE; // Let the user know...
904 }
905
906 /* Now insert it to the global list of messages that can be removed Justin Case there's Trouble */
907 InsertTailList(&usmList, &Message->ListEntry);
908
909 ClearMsgBitsMask(pti, Message->QS_Flags);
910
911 if (Message->HookMessage == MSQ_ISHOOK)
912 { // Direct Hook Call processor
913 Result = co_CallHook( Message->Msg.message, // HookId
914 (INT)(INT_PTR)Message->Msg.hwnd, // Code
915 Message->Msg.wParam,
916 Message->Msg.lParam);
917 }
918 else if(Message->HookMessage == MSQ_INJECTMODULE)
919 {
920 Result = IntLoadHookModule(Message->Msg.message,
921 (HHOOK)Message->Msg.lParam,
922 Message->Msg.wParam);
923 }
924 else if ((Message->CompletionCallback) &&
925 (Message->ptiCallBackSender == pti))
926 { /* Call the callback routine */
927 if (Message->QS_Flags & QS_SMRESULT)
928 {
929 co_IntCallSentMessageCallback(Message->CompletionCallback,
930 Message->Msg.hwnd,
931 Message->Msg.message,
932 Message->CompletionCallbackContext,
933 Message->lResult);
934 /* Set callback to NULL to prevent reentry */
935 Message->CompletionCallback = NULL;
936 }
937 else
938 {
939 /* The message has not been processed yet, reinsert it. */
940 RemoveEntryList(&Message->ListEntry);
941 InsertTailList(&Message->ptiCallBackSender->SentMessagesListHead, &Message->ListEntry);
942 // List is occupied need to set the bit.
943 MsqWakeQueue(Message->ptiCallBackSender, QS_SENDMESSAGE, TRUE);
944 ERR("Callback Message not processed yet. Requeuing the message\n"); //// <---- Need to see if this happens.
945 Ret = FALSE;
946 goto Exit;
947 }
948 }
949 else
950 { /* Call the window procedure. */
951 Result = co_IntSendMessage( Message->Msg.hwnd,
952 Message->Msg.message,
953 Message->Msg.wParam,
954 Message->Msg.lParam);
955 }
956
957 /* If the message is a callback, insert it in the callback senders MessageQueue */
958 if (Message->CompletionCallback)
959 {
960 if (Message->ptiCallBackSender)
961 {
962 Message->lResult = Result;
963 Message->QS_Flags |= QS_SMRESULT;
964
965 /* insert it in the callers message queue */
966 RemoveEntryList(&Message->ListEntry);
967 InsertTailList(&Message->ptiCallBackSender->SentMessagesListHead, &Message->ListEntry);
968 MsqWakeQueue(Message->ptiCallBackSender, QS_SENDMESSAGE, TRUE);
969 }
970 Ret = TRUE;
971 goto Exit;
972 }
973
974 // Retrieve the result from callback.
975 if (Message->QS_Flags & QS_SMRESULT)
976 {
977 Result = Message->lResult;
978 }
979
980 /* Let the sender know the result. */
981 Message->lResult = Result;
982
983 if (Message->HasPackedLParam)
984 {
985 if (Message->Msg.lParam)
986 ExFreePool((PVOID)Message->Msg.lParam);
987 }
988
989 // Clear busy signal.
990 Message->flags &= ~SMF_RECEIVERBUSY;
991
992 /* Notify the sender. */
993 if (Message->pkCompletionEvent != NULL)
994 {
995 KeSetEvent(Message->pkCompletionEvent, IO_NO_INCREMENT, FALSE);
996 }
997
998 /* free the message */
999 if (Message->flags & SMF_RECEIVERFREE)
1000 {
1001 TRACE("Receiver Freeing Message %p\n",Message);
1002 FreeUserMessage(Message);
1003 }
1004
1005 Ret = TRUE;
1006 Exit:
1007 /* do not hangup on the user if this is reentering */
1008 if (!SaveMsg) pti->pcti->CTI_flags &= ~CTI_INSENDMESSAGE;
1009 pti->pusmCurrent = SaveMsg;
1010
1011 return Ret;
1012 }
1013
1014 BOOL FASTCALL
1015 co_MsqSendMessageAsync(PTHREADINFO ptiReceiver,
1016 HWND hwnd,
1017 UINT Msg,
1018 WPARAM wParam,
1019 LPARAM lParam,
1020 SENDASYNCPROC CompletionCallback,
1021 ULONG_PTR CompletionCallbackContext,
1022 BOOL HasPackedLParam,
1023 INT HookMessage)
1024 {
1025
1026 PTHREADINFO ptiSender;
1027 PUSER_SENT_MESSAGE Message;
1028
1029 if(!(Message = AllocateUserMessage(FALSE)))
1030 {
1031 ERR("MsqSendMessageAsync(): Not enough memory to allocate a message");
1032 return FALSE;
1033 }
1034
1035 ptiSender = PsGetCurrentThreadWin32Thread();
1036
1037 Message->Msg.hwnd = hwnd;
1038 Message->Msg.message = Msg;
1039 Message->Msg.wParam = wParam;
1040 Message->Msg.lParam = lParam;
1041 Message->pkCompletionEvent = NULL; // No event needed.
1042 Message->ptiReceiver = ptiReceiver;
1043 Message->ptiCallBackSender = ptiSender;
1044 Message->CompletionCallback = CompletionCallback;
1045 Message->CompletionCallbackContext = CompletionCallbackContext;
1046 Message->HookMessage = HookMessage;
1047 Message->HasPackedLParam = HasPackedLParam;
1048 Message->QS_Flags = QS_SENDMESSAGE;
1049 Message->flags = SMF_RECEIVERFREE;
1050
1051 InsertTailList(&ptiReceiver->SentMessagesListHead, &Message->ListEntry);
1052 MsqWakeQueue(ptiReceiver, QS_SENDMESSAGE, TRUE);
1053
1054 return TRUE;
1055 }
1056
1057 NTSTATUS FASTCALL
1058 co_MsqSendMessage(PTHREADINFO ptirec,
1059 HWND Wnd,
1060 UINT Msg,
1061 WPARAM wParam,
1062 LPARAM lParam,
1063 UINT uTimeout,
1064 BOOL Block,
1065 INT HookMessage,
1066 ULONG_PTR *uResult)
1067 {
1068 PTHREADINFO pti;
1069 PUSER_SENT_MESSAGE SaveMsg, Message;
1070 NTSTATUS WaitStatus;
1071 LARGE_INTEGER Timeout;
1072 PLIST_ENTRY Entry;
1073 PWND pWnd;
1074 BOOLEAN SwapStateEnabled;
1075 LRESULT Result = 0; //// Result could be trashed. ////
1076
1077 pti = PsGetCurrentThreadWin32Thread();
1078 ASSERT(pti != ptirec);
1079 ASSERT(ptirec->pcti); // Send must have a client side to receive it!!!!
1080
1081 /* Don't send from or to a dying thread */
1082 if (pti->TIF_flags & TIF_INCLEANUP || ptirec->TIF_flags & TIF_INCLEANUP)
1083 {
1084 // Unless we are dying and need to tell our parents.
1085 if (pti->TIF_flags & TIF_INCLEANUP && !(ptirec->TIF_flags & TIF_INCLEANUP))
1086 {
1087 // Parent notify is the big one. Fire and forget!
1088 TRACE("Send message from dying thread %u\n", Msg);
1089 co_MsqSendMessageAsync(ptirec, Wnd, Msg, wParam, lParam, NULL, 0, FALSE, HookMessage);
1090 }
1091 if (uResult) *uResult = -1;
1092 TRACE("MsqSM: Msg %u Current pti %lu or Rec pti %lu\n", Msg, pti->TIF_flags & TIF_INCLEANUP, ptirec->TIF_flags & TIF_INCLEANUP);
1093 return STATUS_UNSUCCESSFUL;
1094 }
1095
1096 if (IsThreadSuspended(ptirec))
1097 {
1098 ERR("Sending to Suspended Thread Msg %lx\n",Msg);
1099 if (uResult) *uResult = -1;
1100 return STATUS_UNSUCCESSFUL;
1101 }
1102
1103 // Should we do the same for No Wait?
1104 if ( HookMessage == MSQ_NORMAL )
1105 {
1106 pWnd = ValidateHwndNoErr(Wnd);
1107
1108 // These can not cross International Border lines!
1109 if ( pti->ppi != ptirec->ppi && pWnd )
1110 {
1111 switch(Msg)
1112 {
1113 // Handle the special case when working with password transfers across bordering processes.
1114 case EM_GETLINE:
1115 case EM_SETPASSWORDCHAR:
1116 case WM_GETTEXT:
1117 // Look for edit controls setup for passwords.
1118 if ( gpsi->atomSysClass[ICLS_EDIT] == pWnd->pcls->atomClassName && // Use atomNVClassName.
1119 pWnd->style & ES_PASSWORD )
1120 {
1121 if (uResult) *uResult = -1;
1122 ERR("Running across the border without a passport!\n");
1123 EngSetLastError(ERROR_ACCESS_DENIED);
1124 return STATUS_UNSUCCESSFUL;
1125 }
1126 break;
1127 case WM_NOTIFY:
1128 if (uResult) *uResult = -1;
1129 ERR("Running across the border without a passport!\n");
1130 return STATUS_UNSUCCESSFUL;
1131 }
1132 }
1133
1134 // These can not cross State lines!
1135 if ( Msg == WM_CREATE || Msg == WM_NCCREATE )
1136 {
1137 if (uResult) *uResult = -1;
1138 ERR("Can not tell the other State we have Create!\n");
1139 return STATUS_UNSUCCESSFUL;
1140 }
1141 }
1142
1143 if(!(Message = AllocateUserMessage(TRUE)))
1144 {
1145 ERR("MsqSendMessage(): Not enough memory to allocate a message\n");
1146 if (uResult) *uResult = -1;
1147 return STATUS_INSUFFICIENT_RESOURCES;
1148 }
1149
1150 Timeout.QuadPart = Int32x32To64(-10000,uTimeout); // Pass SMTO test with a TO of 0x80000000.
1151 TRACE("Timeout val %lld\n",Timeout.QuadPart)
1152
1153 Message->Msg.hwnd = Wnd;
1154 Message->Msg.message = Msg;
1155 Message->Msg.wParam = wParam;
1156 Message->Msg.lParam = lParam;
1157 Message->ptiReceiver = ptirec;
1158 Message->ptiSender = pti;
1159 Message->HookMessage = HookMessage;
1160 Message->QS_Flags = QS_SENDMESSAGE;
1161
1162 SaveMsg = pti->pusmSent;
1163 pti->pusmSent = Message;
1164
1165 /* Queue it in the destination's message queue */
1166 InsertTailList(&ptirec->SentMessagesListHead, &Message->ListEntry);
1167
1168 MsqWakeQueue(ptirec, QS_SENDMESSAGE, TRUE);
1169
1170 // First time in, turn off swapping of the stack.
1171 if (pti->cEnterCount == 0)
1172 {
1173 SwapStateEnabled = KeSetKernelStackSwapEnable(FALSE);
1174 }
1175 pti->cEnterCount++;
1176
1177 if (Block)
1178 {
1179 PVOID WaitObjects[2];
1180
1181 WaitObjects[0] = Message->pkCompletionEvent; // Wait 0
1182 WaitObjects[1] = ptirec->pEThread; // Wait 1
1183
1184 UserLeaveCo();
1185
1186 WaitStatus = KeWaitForMultipleObjects( 2,
1187 WaitObjects,
1188 WaitAny,
1189 UserRequest,
1190 UserMode,
1191 FALSE,
1192 (uTimeout ? &Timeout : NULL),
1193 NULL );
1194
1195 UserEnterCo();
1196
1197 if (WaitStatus == STATUS_TIMEOUT)
1198 {
1199 /* Look up if the message has not yet dispatched, if so
1200 make sure it can't pass a result and it must not set the completion event anymore */
1201 Entry = ptirec->SentMessagesListHead.Flink;
1202 while (Entry != &ptirec->SentMessagesListHead)
1203 {
1204 if (CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry) == Message)
1205 {
1206 Message->pkCompletionEvent = NULL;
1207 RemoveEntryList(&Message->ListEntry);
1208 ClearMsgBitsMask(ptirec, Message->QS_Flags);
1209 InsertTailList(&usmList, &Message->ListEntry);
1210 break;
1211 }
1212 Entry = Entry->Flink;
1213 }
1214
1215 ERR("MsqSendMessage (blocked) timed out 1 Status %lx\n", WaitStatus);
1216 }
1217 // Receiving thread passed on and left us hanging with issues still pending.
1218 else if (WaitStatus == STATUS_WAIT_1)
1219 {
1220 ERR("Bk Receiving Thread woken up dead!\n");
1221 Message->flags |= SMF_RECEIVERDIED;
1222 }
1223
1224 while (co_MsqDispatchOneSentMessage(pti))
1225 ;
1226 }
1227 else
1228 {
1229 PVOID WaitObjects[3];
1230
1231 WaitObjects[0] = Message->pkCompletionEvent; // Wait 0
1232 WaitObjects[1] = pti->pEventQueueServer; // Wait 1
1233 WaitObjects[2] = ptirec->pEThread; // Wait 2
1234
1235 do
1236 {
1237 UserLeaveCo();
1238
1239 WaitStatus = KeWaitForMultipleObjects( 3,
1240 WaitObjects,
1241 WaitAny,
1242 UserRequest,
1243 UserMode,
1244 FALSE,
1245 (uTimeout ? &Timeout : NULL),
1246 NULL);
1247
1248 UserEnterCo();
1249
1250 if (WaitStatus == STATUS_TIMEOUT)
1251 {
1252 /* Look up if the message has not yet been dispatched, if so
1253 make sure it can't pass a result and it must not set the completion event anymore */
1254 Entry = ptirec->SentMessagesListHead.Flink;
1255 while (Entry != &ptirec->SentMessagesListHead)
1256 {
1257 if (CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry) == Message)
1258 {
1259 Message->pkCompletionEvent = NULL;
1260 RemoveEntryList(&Message->ListEntry);
1261 ClearMsgBitsMask(ptirec, Message->QS_Flags);
1262 InsertTailList(&usmList, &Message->ListEntry);
1263 break;
1264 }
1265 Entry = Entry->Flink;
1266 }
1267
1268 ERR("MsqSendMessage timed out 2 Status %lx\n", WaitStatus);
1269 break;
1270 }
1271 // Receiving thread passed on and left us hanging with issues still pending.
1272 else if (WaitStatus == STATUS_WAIT_2)
1273 {
1274 ERR("NB Receiving Thread woken up dead!\n");
1275 Message->flags |= SMF_RECEIVERDIED;
1276 break;
1277 }
1278
1279 if (WaitStatus == STATUS_USER_APC) break;
1280
1281 while (co_MsqDispatchOneSentMessage(pti))
1282 ;
1283 } while (WaitStatus == STATUS_WAIT_1);
1284 }
1285
1286 // Count is nil, restore swapping of the stack.
1287 if (--pti->cEnterCount == 0 )
1288 {
1289 KeSetKernelStackSwapEnable(SwapStateEnabled);
1290 }
1291
1292 // Handle User APC
1293 if (WaitStatus == STATUS_USER_APC)
1294 {
1295 // The current thread is dying!
1296 TRACE("User APC\n");
1297
1298 // The Message will be on the Trouble list until Thread cleanup.
1299 Message->flags |= SMF_SENDERDIED;
1300
1301 co_IntDeliverUserAPC();
1302 ERR("User APC Returned\n"); // Should not see this message.
1303 }
1304
1305 // Force this thread to wake up for the next go around.
1306 KeSetEvent(pti->pEventQueueServer, IO_NO_INCREMENT, FALSE);
1307
1308 Result = Message->lResult;
1309
1310 // Determine whether this message is being processed or not.
1311 if ((Message->flags & (SMF_RECEIVERBUSY|SMF_RECEIVEDMESSAGE)) != SMF_RECEIVEDMESSAGE)
1312 {
1313 Message->flags |= SMF_RECEIVERFREE;
1314 }
1315
1316 if (!(Message->flags & SMF_RECEIVERFREE))
1317 {
1318 TRACE("Sender Freeing Message %p ptirec %p bit %d list empty %d\n",Message,ptirec,!!(ptirec->pcti->fsChangeBits & QS_SENDMESSAGE),IsListEmpty(&ptirec->SentMessagesListHead));
1319 // Make it to this point, the message was received.
1320 FreeUserMessage(Message);
1321 }
1322
1323 pti->pusmSent = SaveMsg;
1324
1325 TRACE("MSM Allocation Count %d Status %lx Result %d\n",SendMsgCount,WaitStatus,Result);
1326
1327 if (WaitStatus != STATUS_TIMEOUT)
1328 {
1329 if (uResult)
1330 {
1331 *uResult = (STATUS_WAIT_0 == WaitStatus ? Result : 0);
1332 }
1333 }
1334
1335 return WaitStatus;
1336 }
1337
1338 VOID FASTCALL
1339 MsqPostMessage(PTHREADINFO pti,
1340 MSG* Msg,
1341 BOOLEAN HardwareMessage,
1342 DWORD MessageBits,
1343 DWORD dwQEvent,
1344 LONG_PTR ExtraInfo)
1345 {
1346 PUSER_MESSAGE Message;
1347 PUSER_MESSAGE_QUEUE MessageQueue;
1348
1349 if ( pti->TIF_flags & TIF_INCLEANUP || pti->MessageQueue->QF_flags & QF_INDESTROY )
1350 {
1351 ERR("Post Msg; Thread or Q is Dead!\n");
1352 return;
1353 }
1354
1355 if(!(Message = MsqCreateMessage(Msg)))
1356 {
1357 return;
1358 }
1359
1360 MessageQueue = pti->MessageQueue;
1361
1362 if (!HardwareMessage)
1363 {
1364 InsertTailList(&pti->PostedMessagesListHead, &Message->ListEntry);
1365 }
1366 else
1367 {
1368 InsertTailList(&MessageQueue->HardwareMessagesListHead, &Message->ListEntry);
1369 }
1370
1371 if (Msg->message == WM_HOTKEY) MessageBits |= QS_HOTKEY; // Justin Case, just set it.
1372 Message->dwQEvent = dwQEvent;
1373 Message->ExtraInfo = ExtraInfo;
1374 Message->QS_Flags = MessageBits;
1375 Message->pti = pti;
1376 MsqWakeQueue(pti, MessageBits, TRUE);
1377 }
1378
1379 VOID FASTCALL
1380 MsqPostQuitMessage(PTHREADINFO pti, ULONG ExitCode)
1381 {
1382 pti->QuitPosted = TRUE;
1383 pti->exitCode = ExitCode;
1384 MsqWakeQueue(pti, QS_POSTMESSAGE|QS_ALLPOSTMESSAGE, TRUE);
1385 }
1386
1387 /***********************************************************************
1388 * MsqSendParentNotify
1389 *
1390 * Send a WM_PARENTNOTIFY to all ancestors of the given window, unless
1391 * the window has the WS_EX_NOPARENTNOTIFY style.
1392 */
1393 static void MsqSendParentNotify( PWND pwnd, WORD event, WORD idChild, POINT pt )
1394 {
1395 PWND pwndDesktop = UserGetDesktopWindow();
1396
1397 /* pt has to be in the client coordinates of the parent window */
1398 pt.x += pwndDesktop->rcClient.left - pwnd->rcClient.left;
1399 pt.y += pwndDesktop->rcClient.top - pwnd->rcClient.top;
1400
1401 for (;;)
1402 {
1403 PWND pwndParent;
1404
1405 if (!(pwnd->style & WS_CHILD)) break;
1406 if (pwnd->ExStyle & WS_EX_NOPARENTNOTIFY) break;
1407 if (!(pwndParent = IntGetParent(pwnd))) break;
1408 if (pwndParent == pwndDesktop) break;
1409 pt.x += pwnd->rcClient.left - pwndParent->rcClient.left;
1410 pt.y += pwnd->rcClient.top - pwndParent->rcClient.top;
1411
1412 pwnd = pwndParent;
1413 co_IntSendMessage( UserHMGetHandle(pwnd), WM_PARENTNOTIFY,
1414 MAKEWPARAM( event, idChild ), MAKELPARAM( pt.x, pt.y ) );
1415 }
1416 }
1417
1418 VOID
1419 FASTCALL
1420 IntTrackMouseMove(PWND pwndTrack, PDESKTOP pDesk, PMSG msg, USHORT hittest)
1421 {
1422 // PWND pwndTrack = IntChildrenWindowFromPoint(pwndMsg, msg->pt.x, msg->pt.y);
1423 // hittest = (USHORT)GetNCHitEx(pwndTrack, msg->pt); /// @todo WTF is this???
1424
1425 if ( pDesk->spwndTrack != pwndTrack || // Change with tracking window or
1426 msg->message != WM_MOUSEMOVE || // Mouse click changes or
1427 pDesk->htEx != hittest) // Change in current hit test states.
1428 {
1429 TRACE("ITMM: Track Mouse Move!\n");
1430
1431 /* Handle only the changing window track and mouse move across a border. */
1432 if ( pDesk->spwndTrack != pwndTrack ||
1433 (pDesk->htEx == HTCLIENT) ^ (hittest == HTCLIENT) )
1434 {
1435 TRACE("ITMM: Another Wnd %d or Across Border %d\n",
1436 pDesk->spwndTrack != pwndTrack,(pDesk->htEx == HTCLIENT) ^ (hittest == HTCLIENT));
1437
1438 if ( pDesk->dwDTFlags & DF_TME_LEAVE )
1439 UserPostMessage( UserHMGetHandle(pDesk->spwndTrack),
1440 (pDesk->htEx != HTCLIENT) ? WM_NCMOUSELEAVE : WM_MOUSELEAVE,
1441 0, 0);
1442
1443 if ( pDesk->dwDTFlags & DF_TME_HOVER )
1444 IntKillTimer(pDesk->spwndTrack, ID_EVENT_SYSTIMER_MOUSEHOVER, TRUE);
1445
1446 /* Clear the flags to sign a change. */
1447 pDesk->dwDTFlags &= ~(DF_TME_LEAVE|DF_TME_HOVER);
1448 }
1449 /* Set the Track window and hit test. */
1450 pDesk->spwndTrack = pwndTrack;
1451 pDesk->htEx = hittest;
1452 }
1453
1454 /* Reset, Same Track window, Hover set and Mouse Clicks or Clobbered Hover box. */
1455 if ( pDesk->spwndTrack == pwndTrack &&
1456 ( msg->message != WM_MOUSEMOVE || !RECTL_bPointInRect(&pDesk->rcMouseHover, msg->pt.x, msg->pt.y)) &&
1457 pDesk->dwDTFlags & DF_TME_HOVER )
1458 {
1459 TRACE("ITMM: Reset Hover points!\n");
1460 // Restart timer for the hover period.
1461 IntSetTimer(pDesk->spwndTrack, ID_EVENT_SYSTIMER_MOUSEHOVER, pDesk->dwMouseHoverTime, SystemTimerProc, TMRF_SYSTEM);
1462 // Reset desktop mouse hover from the system default hover rectangle.
1463 RECTL_vSetRect(&pDesk->rcMouseHover,
1464 msg->pt.x - gspv.iMouseHoverWidth / 2,
1465 msg->pt.y - gspv.iMouseHoverHeight / 2,
1466 msg->pt.x + gspv.iMouseHoverWidth / 2,
1467 msg->pt.y + gspv.iMouseHoverHeight / 2);
1468 }
1469 }
1470
1471 BOOL co_IntProcessMouseMessage(MSG* msg, BOOL* RemoveMessages, BOOL* NotForUs, UINT first, UINT last)
1472 {
1473 MSG clk_msg;
1474 POINT pt;
1475 UINT message;
1476 USHORT hittest;
1477 EVENTMSG event;
1478 MOUSEHOOKSTRUCT hook;
1479 BOOL eatMsg = FALSE;
1480
1481 PWND pwndMsg, pwndDesktop;
1482 PUSER_MESSAGE_QUEUE MessageQueue;
1483 PTHREADINFO pti;
1484 PSYSTEM_CURSORINFO CurInfo;
1485 PDESKTOP pDesk;
1486
1487 pti = PsGetCurrentThreadWin32Thread();
1488 pwndDesktop = UserGetDesktopWindow();
1489 MessageQueue = pti->MessageQueue;
1490 CurInfo = IntGetSysCursorInfo();
1491 pwndMsg = ValidateHwndNoErr(msg->hwnd);
1492 clk_msg = MessageQueue->msgDblClk;
1493 pDesk = pwndDesktop->head.rpdesk;
1494
1495 /* find the window to dispatch this mouse message to */
1496 if (MessageQueue->spwndCapture)
1497 {
1498 hittest = HTCLIENT;
1499 pwndMsg = MessageQueue->spwndCapture;
1500 }
1501 else
1502 {
1503 /*
1504 Start with null window. See wine win.c:test_mouse_input:WM_COMMAND tests.
1505 */
1506 pwndMsg = co_WinPosWindowFromPoint( NULL, &msg->pt, &hittest, FALSE);
1507 }
1508
1509 TRACE("Got mouse message for %p, hittest: 0x%x\n", msg->hwnd, hittest);
1510
1511 // Null window or not the same "Hardware" message queue.
1512 if (pwndMsg == NULL || pwndMsg->head.pti->MessageQueue != MessageQueue)
1513 {
1514 // Crossing a boundary, so set cursor. See default message queue cursor.
1515 UserSetCursor(SYSTEMCUR(ARROW), FALSE);
1516 /* Remove and ignore the message */
1517 *RemoveMessages = TRUE;
1518 return FALSE;
1519 }
1520
1521 // Check to see if this is attached,
1522 if ( pwndMsg->head.pti != pti && // window thread is not current,
1523 MessageQueue->cThreads > 1 ) // and is attached...
1524 {
1525 // This is not for us and we should leave so the other thread can check for messages!!!
1526 *NotForUs = TRUE;
1527 *RemoveMessages = TRUE;
1528 return FALSE;
1529 }
1530
1531 if ( MessageQueue == gpqCursor ) // Cursor must use the same Queue!
1532 {
1533 IntTrackMouseMove(pwndMsg, pDesk, msg, hittest);
1534 }
1535 else
1536 {
1537 ERR("Not the same cursor!\n");
1538 }
1539
1540 msg->hwnd = UserHMGetHandle(pwndMsg);
1541
1542 pt = msg->pt;
1543 message = msg->message;
1544
1545 /* Note: windows has no concept of a non-client wheel message */
1546 if (message != WM_MOUSEWHEEL)
1547 {
1548 if (hittest != HTCLIENT)
1549 {
1550 message += WM_NCMOUSEMOVE - WM_MOUSEMOVE;
1551 msg->wParam = hittest; // Caution! This might break wParam check in DblClk.
1552 }
1553 else
1554 {
1555 /* coordinates don't get translated while tracking a menu */
1556 /* FIXME: should differentiate popups and top-level menus */
1557 if (!(MessageQueue->MenuOwner))
1558 {
1559 pt.x += pwndDesktop->rcClient.left - pwndMsg->rcClient.left;
1560 pt.y += pwndDesktop->rcClient.top - pwndMsg->rcClient.top;
1561 }
1562 }
1563 }
1564 msg->lParam = MAKELONG( pt.x, pt.y );
1565
1566 /* translate double clicks */
1567
1568 if ((msg->message == WM_LBUTTONDOWN) ||
1569 (msg->message == WM_RBUTTONDOWN) ||
1570 (msg->message == WM_MBUTTONDOWN) ||
1571 (msg->message == WM_XBUTTONDOWN))
1572 {
1573 BOOL update = *RemoveMessages;
1574
1575 /* translate double clicks -
1576 * note that ...MOUSEMOVEs can slip in between
1577 * ...BUTTONDOWN and ...BUTTONDBLCLK messages */
1578
1579 if ((MessageQueue->MenuOwner || MessageQueue->MoveSize) ||
1580 hittest != HTCLIENT ||
1581 (pwndMsg->pcls->style & CS_DBLCLKS))
1582 {
1583 if ((msg->message == clk_msg.message) &&
1584 (msg->hwnd == clk_msg.hwnd) &&
1585 // Only worry about XButton wParam.
1586 (msg->message != WM_XBUTTONDOWN || GET_XBUTTON_WPARAM(msg->wParam) == GET_XBUTTON_WPARAM(clk_msg.wParam)) &&
1587 ((msg->time - clk_msg.time) < (ULONG)gspv.iDblClickTime) &&
1588 (abs(msg->pt.x - clk_msg.pt.x) < UserGetSystemMetrics(SM_CXDOUBLECLK)/2) &&
1589 (abs(msg->pt.y - clk_msg.pt.y) < UserGetSystemMetrics(SM_CYDOUBLECLK)/2))
1590 {
1591 message += (WM_LBUTTONDBLCLK - WM_LBUTTONDOWN);
1592 if (update)
1593 {
1594 MessageQueue->msgDblClk.message = 0; /* clear the double click conditions */
1595 update = FALSE;
1596 }
1597 }
1598 }
1599
1600 if (!((first == 0 && last == 0) || (message >= first || message <= last)))
1601 {
1602 TRACE("Message out of range!!!\n");
1603 return FALSE;
1604 }
1605
1606 /* update static double click conditions */
1607 if (update) MessageQueue->msgDblClk = *msg;
1608 }
1609 else
1610 {
1611 if (!((first == 0 && last == 0) || (message >= first || message <= last)))
1612 {
1613 TRACE("Message out of range!!!\n");
1614 return FALSE;
1615 }
1616
1617 // Update mouse move down keys.
1618 if (message == WM_MOUSEMOVE)
1619 {
1620 msg->wParam = MsqGetDownKeyState(MessageQueue);
1621 }
1622 }
1623
1624 if (gspv.bMouseClickLock)
1625 {
1626 BOOL IsClkLck = FALSE;
1627
1628 if(msg->message == WM_LBUTTONUP)
1629 {
1630 IsClkLck = ((msg->time - CurInfo->ClickLockTime) >= gspv.dwMouseClickLockTime);
1631 if (IsClkLck && (!CurInfo->ClickLockActive))
1632 {
1633 CurInfo->ClickLockActive = TRUE;
1634 }
1635 }
1636 else if (msg->message == WM_LBUTTONDOWN)
1637 {
1638 if (CurInfo->ClickLockActive)
1639 {
1640 IsClkLck = TRUE;
1641 CurInfo->ClickLockActive = FALSE;
1642 }
1643
1644 CurInfo->ClickLockTime = msg->time;
1645 }
1646
1647 if(IsClkLck)
1648 {
1649 /* Remove and ignore the message */
1650 *RemoveMessages = TRUE;
1651 TRACE("Remove and ignore the message\n");
1652 return FALSE;
1653 }
1654 }
1655
1656 /* message is accepted now (but still get dropped) */
1657
1658 event.message = msg->message;
1659 event.time = msg->time;
1660 event.hwnd = msg->hwnd;
1661 event.paramL = msg->pt.x;
1662 event.paramH = msg->pt.y;
1663 co_HOOK_CallHooks( WH_JOURNALRECORD, HC_ACTION, 0, (LPARAM)&event );
1664
1665 hook.pt = msg->pt;
1666 hook.hwnd = msg->hwnd;
1667 hook.wHitTestCode = hittest;
1668 hook.dwExtraInfo = 0 /* extra_info */ ;
1669 if (co_HOOK_CallHooks( WH_MOUSE, *RemoveMessages ? HC_ACTION : HC_NOREMOVE,
1670 message, (LPARAM)&hook ))
1671 {
1672 hook.pt = msg->pt;
1673 hook.hwnd = msg->hwnd;
1674 hook.wHitTestCode = hittest;
1675 hook.dwExtraInfo = 0 /* extra_info */ ;
1676 co_HOOK_CallHooks( WH_CBT, HCBT_CLICKSKIPPED, message, (LPARAM)&hook );
1677
1678 ERR("WH_MOUSE dropped mouse message!\n");
1679
1680 /* Remove and skip message */
1681 *RemoveMessages = TRUE;
1682 return FALSE;
1683 }
1684
1685 if ((hittest == (USHORT)HTERROR) || (hittest == (USHORT)HTNOWHERE))
1686 {
1687 co_IntSendMessage( msg->hwnd, WM_SETCURSOR, (WPARAM)msg->hwnd, MAKELONG( hittest, msg->message ));
1688
1689 /* Remove and skip message */
1690 *RemoveMessages = TRUE;
1691 return FALSE;
1692 }
1693
1694 if ((*RemoveMessages == FALSE) || MessageQueue->spwndCapture)
1695 {
1696 /* Accept the message */
1697 msg->message = message;
1698 return TRUE;
1699 }
1700
1701 if ((msg->message == WM_LBUTTONDOWN) ||
1702 (msg->message == WM_RBUTTONDOWN) ||
1703 (msg->message == WM_MBUTTONDOWN) ||
1704 (msg->message == WM_XBUTTONDOWN))
1705 {
1706 /* Send the WM_PARENTNOTIFY,
1707 * note that even for double/nonclient clicks
1708 * notification message is still WM_L/M/RBUTTONDOWN.
1709 */
1710 MsqSendParentNotify(pwndMsg, msg->message, 0, msg->pt );
1711
1712 /* Activate the window if needed */
1713
1714 if (pwndMsg != MessageQueue->spwndActive)
1715 {
1716 PWND pwndTop = pwndMsg;
1717 pwndTop = IntGetNonChildAncestor(pwndTop);
1718
1719 TRACE("Mouse pti %p pwndMsg pti %p pwndTop pti %p\n",MessageQueue->ptiMouse,pwndMsg->head.pti,pwndTop->head.pti);
1720
1721 if (pwndTop && pwndTop != pwndDesktop)
1722 {
1723 LONG ret = co_IntSendMessage( msg->hwnd,
1724 WM_MOUSEACTIVATE,
1725 (WPARAM)UserHMGetHandle(pwndTop),
1726 MAKELONG( hittest, msg->message));
1727 switch(ret)
1728 {
1729 case MA_NOACTIVATEANDEAT:
1730 eatMsg = TRUE;
1731 /* fall through */
1732 case MA_NOACTIVATE:
1733 break;
1734 case MA_ACTIVATEANDEAT:
1735 eatMsg = TRUE;
1736 /* fall through */
1737 case MA_ACTIVATE:
1738 case 0:
1739 if (!co_IntMouseActivateWindow( pwndTop )) eatMsg = TRUE;
1740 break;
1741 default:
1742 ERR( "unknown WM_MOUSEACTIVATE code %d\n", ret );
1743 break;
1744 }
1745 }
1746 }
1747 }
1748
1749 /* send the WM_SETCURSOR message */
1750
1751 /* Windows sends the normal mouse message as the message parameter
1752 in the WM_SETCURSOR message even if it's non-client mouse message */
1753 co_IntSendMessage( msg->hwnd, WM_SETCURSOR, (WPARAM)msg->hwnd, MAKELONG( hittest, msg->message ));
1754
1755 msg->message = message;
1756 return !eatMsg;
1757 }
1758
1759 BOOL co_IntProcessKeyboardMessage(MSG* Msg, BOOL* RemoveMessages)
1760 {
1761 EVENTMSG Event;
1762 USER_REFERENCE_ENTRY Ref;
1763 PWND pWnd;
1764 UINT ImmRet;
1765 BOOL Ret = TRUE;
1766 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
1767
1768 if (Msg->message == VK_PACKET)
1769 {
1770 pti->wchInjected = HIWORD(Msg->wParam);
1771 }
1772
1773 if (Msg->message == WM_KEYDOWN || Msg->message == WM_SYSKEYDOWN ||
1774 Msg->message == WM_KEYUP || Msg->message == WM_SYSKEYUP)
1775 {
1776 switch (Msg->wParam)
1777 {
1778 case VK_LSHIFT: case VK_RSHIFT:
1779 Msg->wParam = VK_SHIFT;
1780 break;
1781 case VK_LCONTROL: case VK_RCONTROL:
1782 Msg->wParam = VK_CONTROL;
1783 break;
1784 case VK_LMENU: case VK_RMENU:
1785 Msg->wParam = VK_MENU;
1786 break;
1787 }
1788 }
1789
1790 pWnd = ValidateHwndNoErr(Msg->hwnd);
1791 if (pWnd) UserRefObjectCo(pWnd, &Ref);
1792
1793 Event.message = Msg->message;
1794 Event.hwnd = Msg->hwnd;
1795 Event.time = Msg->time;
1796 Event.paramL = (Msg->wParam & 0xFF) | (HIWORD(Msg->lParam) << 8);
1797 Event.paramH = Msg->lParam & 0x7FFF;
1798 if (HIWORD(Msg->lParam) & 0x0100) Event.paramH |= 0x8000;
1799 co_HOOK_CallHooks( WH_JOURNALRECORD, HC_ACTION, 0, (LPARAM)&Event);
1800
1801 if (*RemoveMessages)
1802 {
1803 if ((Msg->message == WM_KEYDOWN) &&
1804 (Msg->hwnd != IntGetDesktopWindow()))
1805 {
1806 /* Handle F1 key by sending out WM_HELP message */
1807 if (Msg->wParam == VK_F1)
1808 {
1809 UserPostMessage( Msg->hwnd, WM_KEYF1, 0, 0 );
1810 }
1811 else if (Msg->wParam >= VK_BROWSER_BACK &&
1812 Msg->wParam <= VK_LAUNCH_APP2)
1813 {
1814 /* FIXME: Process keystate */
1815 co_IntSendMessage(Msg->hwnd, WM_APPCOMMAND, (WPARAM)Msg->hwnd, MAKELPARAM(0, (FAPPCOMMAND_KEY | (Msg->wParam - VK_BROWSER_BACK + 1))));
1816 }
1817 }
1818 else if (Msg->message == WM_KEYUP)
1819 {
1820 /* Handle VK_APPS key by posting a WM_CONTEXTMENU message */
1821 if (Msg->wParam == VK_APPS && pti->MessageQueue->MenuOwner == NULL)
1822 UserPostMessage( Msg->hwnd, WM_CONTEXTMENU, (WPARAM)Msg->hwnd, -1 );
1823 }
1824 }
1825
1826 if (co_HOOK_CallHooks( WH_KEYBOARD,
1827 *RemoveMessages ? HC_ACTION : HC_NOREMOVE,
1828 LOWORD(Msg->wParam),
1829 Msg->lParam))
1830 {
1831 /* skip this message */
1832 co_HOOK_CallHooks( WH_CBT,
1833 HCBT_KEYSKIPPED,
1834 LOWORD(Msg->wParam),
1835 Msg->lParam );
1836
1837 ERR("KeyboardMessage WH_KEYBOARD Call Hook return!\n");
1838
1839 *RemoveMessages = TRUE;
1840
1841 Ret = FALSE;
1842 }
1843
1844 if ( pWnd && Ret && *RemoveMessages && Msg->message == WM_KEYDOWN && !(pti->TIF_flags & TIF_DISABLEIME))
1845 {
1846 if ( (ImmRet = IntImmProcessKey(pti->MessageQueue, pWnd, Msg->message, Msg->wParam, Msg->lParam)) )
1847 {
1848 if ( ImmRet & (IPHK_HOTKEY|IPHK_SKIPTHISKEY) )
1849 {
1850 ImmRet = 0;
1851 }
1852 if ( ImmRet & IPHK_PROCESSBYIME )
1853 {
1854 Msg->wParam = VK_PROCESSKEY;
1855 }
1856 }
1857 }
1858
1859 if (pWnd) UserDerefObjectCo(pWnd);
1860 return Ret;
1861 }
1862
1863 BOOL co_IntProcessHardwareMessage(MSG* Msg, BOOL* RemoveMessages, BOOL* NotForUs, UINT first, UINT last)
1864 {
1865 if ( IS_MOUSE_MESSAGE(Msg->message))
1866 {
1867 return co_IntProcessMouseMessage(Msg, RemoveMessages, NotForUs, first, last);
1868 }
1869 else if ( IS_KBD_MESSAGE(Msg->message))
1870 {
1871 return co_IntProcessKeyboardMessage(Msg, RemoveMessages);
1872 }
1873
1874 return TRUE;
1875 }
1876
1877 /* check whether a message filter contains at least one potential hardware message */
1878 static INT FASTCALL
1879 filter_contains_hw_range( UINT first, UINT last )
1880 {
1881 /* hardware message ranges are (in numerical order):
1882 * WM_NCMOUSEFIRST .. WM_NCMOUSELAST
1883 * WM_KEYFIRST .. WM_KEYLAST
1884 * WM_MOUSEFIRST .. WM_MOUSELAST
1885 */
1886 if (!last) --last;
1887 if (last < WM_NCMOUSEFIRST) return 0;
1888 if (first > WM_NCMOUSELAST && last < WM_KEYFIRST) return 0;
1889 if (first > WM_KEYLAST && last < WM_MOUSEFIRST) return 0;
1890 if (first > WM_MOUSELAST) return 0;
1891 return 1;
1892 }
1893
1894 BOOL APIENTRY
1895 co_MsqPeekHardwareMessage(IN PTHREADINFO pti,
1896 IN BOOL Remove,
1897 IN PWND Window,
1898 IN UINT MsgFilterLow,
1899 IN UINT MsgFilterHigh,
1900 IN UINT QSflags,
1901 OUT MSG* pMsg)
1902 {
1903 BOOL AcceptMessage, NotForUs;
1904 PUSER_MESSAGE CurrentMessage;
1905 PLIST_ENTRY ListHead;
1906 MSG msg;
1907 ULONG_PTR idSave;
1908 DWORD QS_Flags;
1909 BOOL Ret = FALSE;
1910 PUSER_MESSAGE_QUEUE MessageQueue = pti->MessageQueue;
1911
1912 if (!filter_contains_hw_range( MsgFilterLow, MsgFilterHigh )) return FALSE;
1913
1914 ListHead = MessageQueue->HardwareMessagesListHead.Flink;
1915
1916 if (IsListEmpty(ListHead)) return FALSE;
1917
1918 if (!MessageQueue->ptiSysLock)
1919 {
1920 MessageQueue->ptiSysLock = pti;
1921 pti->pcti->CTI_flags |= CTI_THREADSYSLOCK;
1922 }
1923
1924 if (MessageQueue->ptiSysLock != pti)
1925 {
1926 ERR("Thread Q is locked to ptiSysLock 0x%p pti 0x%p\n",MessageQueue->ptiSysLock,pti);
1927 return FALSE;
1928 }
1929
1930 while (ListHead != &MessageQueue->HardwareMessagesListHead)
1931 {
1932 CurrentMessage = CONTAINING_RECORD(ListHead, USER_MESSAGE, ListEntry);
1933 ListHead = ListHead->Flink;
1934
1935 if (MessageQueue->idSysPeek == (ULONG_PTR)CurrentMessage)
1936 {
1937 TRACE("Skip this message due to it is in play!\n");
1938 continue;
1939 }
1940 /*
1941 MSDN:
1942 1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL.
1943 2: retrieves only messages on the current thread's message queue whose hwnd value is NULL.
1944 3: handle to the window whose messages are to be retrieved.
1945 */
1946 if ( ( !Window || // 1
1947 ( Window == PWND_BOTTOM && CurrentMessage->Msg.hwnd == NULL ) || // 2
1948 ( Window != PWND_BOTTOM && Window->head.h == CurrentMessage->Msg.hwnd ) || // 3
1949 ( CurrentMessage->Msg.message == WM_MOUSEMOVE ) ) && // Null window for mouse moves.
1950 ( ( ( MsgFilterLow == 0 && MsgFilterHigh == 0 ) && CurrentMessage->QS_Flags & QSflags ) ||
1951 ( MsgFilterLow <= CurrentMessage->Msg.message && MsgFilterHigh >= CurrentMessage->Msg.message ) ) )
1952 {
1953 idSave = MessageQueue->idSysPeek;
1954 MessageQueue->idSysPeek = (ULONG_PTR)CurrentMessage;
1955
1956 msg = CurrentMessage->Msg;
1957 QS_Flags = CurrentMessage->QS_Flags;
1958
1959 NotForUs = FALSE;
1960
1961 UpdateKeyStateFromMsg(MessageQueue, &msg);
1962 AcceptMessage = co_IntProcessHardwareMessage(&msg, &Remove, &NotForUs, MsgFilterLow, MsgFilterHigh);
1963
1964 if (Remove)
1965 {
1966 if (CurrentMessage->pti != NULL)
1967 {
1968 RemoveEntryList(&CurrentMessage->ListEntry);
1969 MsqDestroyMessage(CurrentMessage);
1970 }
1971 ClearMsgBitsMask(pti, QS_Flags);
1972 }
1973
1974 MessageQueue->idSysPeek = idSave;
1975
1976 if (NotForUs)
1977 {
1978 Ret = FALSE;
1979 break;
1980 }
1981
1982 if (AcceptMessage)
1983 {
1984 *pMsg = msg;
1985 // Fix all but one wine win:test_GetMessagePos WM_TIMER tests. See PostTimerMessages.
1986 if (!RtlEqualMemory(&pti->ptLast, &msg.pt, sizeof(POINT)))
1987 {
1988 pti->TIF_flags |= TIF_MSGPOSCHANGED;
1989 }
1990 pti->ptLast = msg.pt;
1991 pti->timeLast = msg.time;
1992 MessageQueue->ExtraInfo = ExtraInfo;
1993 Ret = TRUE;
1994 break;
1995 }
1996 }
1997 }
1998
1999 MessageQueue->ptiSysLock = NULL;
2000 pti->pcti->CTI_flags &= ~CTI_THREADSYSLOCK;
2001 return Ret;
2002 }
2003
2004 BOOLEAN APIENTRY
2005 MsqPeekMessage(IN PTHREADINFO pti,
2006 IN BOOLEAN Remove,
2007 IN PWND Window,
2008 IN UINT MsgFilterLow,
2009 IN UINT MsgFilterHigh,
2010 IN UINT QSflags,
2011 OUT LONG_PTR *ExtraInfo,
2012 OUT PMSG Message)
2013 {
2014 PUSER_MESSAGE CurrentMessage;
2015 PLIST_ENTRY ListHead;
2016 DWORD QS_Flags;
2017 BOOL Ret = FALSE;
2018
2019 ListHead = pti->PostedMessagesListHead.Flink;
2020
2021 if (IsListEmpty(ListHead)) return FALSE;
2022
2023 while(ListHead != &pti->PostedMessagesListHead)
2024 {
2025 CurrentMessage = CONTAINING_RECORD(ListHead, USER_MESSAGE, ListEntry);
2026 ListHead = ListHead->Flink;
2027 /*
2028 MSDN:
2029 1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL.
2030 2: retrieves only messages on the current thread's message queue whose hwnd value is NULL.
2031 3: handle to the window whose messages are to be retrieved.
2032 */
2033 if ( ( !Window || // 1
2034 ( Window == PWND_BOTTOM && CurrentMessage->Msg.hwnd == NULL ) || // 2
2035 ( Window != PWND_BOTTOM && Window->head.h == CurrentMessage->Msg.hwnd ) ) && // 3
2036 ( ( ( MsgFilterLow == 0 && MsgFilterHigh == 0 ) && CurrentMessage->QS_Flags & QSflags ) ||
2037 ( MsgFilterLow <= CurrentMessage->Msg.message && MsgFilterHigh >= CurrentMessage->Msg.message ) ) )
2038 {
2039 *Message = CurrentMessage->Msg;
2040 *ExtraInfo = CurrentMessage->ExtraInfo;
2041 QS_Flags = CurrentMessage->QS_Flags;
2042
2043 if (Remove)
2044 {
2045 if (CurrentMessage->pti != NULL)
2046 {
2047 RemoveEntryList(&CurrentMessage->ListEntry);
2048 MsqDestroyMessage(CurrentMessage);
2049 }
2050 ClearMsgBitsMask(pti, QS_Flags);
2051 }
2052 Ret = TRUE;
2053 break;
2054 }
2055 }
2056
2057 return Ret;
2058 }
2059
2060 NTSTATUS FASTCALL
2061 co_MsqWaitForNewMessages(PTHREADINFO pti, PWND WndFilter,
2062 UINT MsgFilterMin, UINT MsgFilterMax)
2063 {
2064 NTSTATUS ret = STATUS_SUCCESS;
2065
2066 // Post mouse moves before waiting for messages.
2067 if (pti->MessageQueue->QF_flags & QF_MOUSEMOVED)
2068 {
2069 IntCoalesceMouseMove(pti);
2070 }
2071
2072 UserLeaveCo();
2073
2074 ZwYieldExecution(); // Let someone else run!
2075
2076 ret = KeWaitForSingleObject( pti->pEventQueueServer,
2077 UserRequest,
2078 UserMode,
2079 FALSE,
2080 NULL );
2081 UserEnterCo();
2082 if ( ret == STATUS_USER_APC )
2083 {
2084 TRACE("MWFNW User APC\n");
2085 co_IntDeliverUserAPC();
2086 }
2087 return ret;
2088 }
2089
2090 BOOL FASTCALL
2091 MsqIsHung(PTHREADINFO pti)
2092 {
2093 LARGE_INTEGER LargeTickCount;
2094
2095 KeQueryTickCount(&LargeTickCount);
2096
2097 if ((LargeTickCount.u.LowPart - pti->timeLast) > MSQ_HUNG &&
2098 !(pti->pcti->fsWakeMask & QS_INPUT) &&
2099 !PsGetThreadFreezeCount(pti->pEThread) &&
2100 !(pti->ppi->W32PF_flags & W32PF_APPSTARTING))
2101 return TRUE;
2102
2103 return FALSE;
2104 }
2105
2106 BOOL FASTCALL
2107 IsThreadSuspended(PTHREADINFO pti)
2108 {
2109 if (pti->pEThread)
2110 {
2111 BOOL Ret = TRUE;
2112 ObReferenceObject(pti->pEThread);
2113 if (!(pti->pEThread->Tcb.SuspendCount) && !PsGetThreadFreezeCount(pti->pEThread)) Ret = FALSE;
2114 ObDereferenceObject(pti->pEThread);
2115 return Ret;
2116 }
2117 return FALSE;
2118 }
2119
2120 VOID
2121 CALLBACK
2122 HungAppSysTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
2123 {
2124 DoTheScreenSaver();
2125 TRACE("HungAppSysTimerProc\n");
2126 // Process list of windows that are hung and waiting.
2127 }
2128
2129 BOOLEAN FASTCALL
2130 MsqInitializeMessageQueue(PTHREADINFO pti, PUSER_MESSAGE_QUEUE MessageQueue)
2131 {
2132 InitializeListHead(&MessageQueue->HardwareMessagesListHead); // Keep here!
2133 MessageQueue->spwndFocus = NULL;
2134 MessageQueue->iCursorLevel = 0;
2135 MessageQueue->CursorObject = SYSTEMCUR(WAIT); // See test_initial_cursor.
2136 if (MessageQueue->CursorObject)
2137 {
2138 TRACE("Default cursor hcur %p\n",UserHMGetHandle(MessageQueue->CursorObject));
2139 UserReferenceObject(MessageQueue->CursorObject);
2140 }
2141 RtlCopyMemory(MessageQueue->afKeyState, gafAsyncKeyState, sizeof(gafAsyncKeyState));
2142 MessageQueue->ptiMouse = pti;
2143 MessageQueue->ptiKeyboard = pti;
2144 MessageQueue->cThreads++;
2145
2146 return TRUE;
2147 }
2148
2149 VOID FASTCALL
2150 MsqCleanupThreadMsgs(PTHREADINFO pti)
2151 {
2152 PLIST_ENTRY CurrentEntry;
2153 PUSER_MESSAGE CurrentMessage;
2154 PUSER_SENT_MESSAGE CurrentSentMessage;
2155
2156 TRACE("MsqCleanupThreadMsgs %p\n",pti);
2157
2158 // Clear it all out.
2159 if (pti->pcti)
2160 {
2161 pti->pcti->fsWakeBits = 0;
2162 pti->pcti->fsChangeBits = 0;
2163 }
2164
2165 pti->nCntsQBits[QSRosKey] = 0;
2166 pti->nCntsQBits[QSRosMouseMove] = 0;
2167 pti->nCntsQBits[QSRosMouseButton] = 0;
2168 pti->nCntsQBits[QSRosPostMessage] = 0;
2169 pti->nCntsQBits[QSRosSendMessage] = 0;
2170 pti->nCntsQBits[QSRosHotKey] = 0;
2171 pti->nCntsQBits[QSRosEvent] = 0;
2172
2173 /* cleanup posted messages */
2174 while (!IsListEmpty(&pti->PostedMessagesListHead))
2175 {
2176 CurrentEntry = RemoveHeadList(&pti->PostedMessagesListHead);
2177 CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE, ListEntry);
2178 if (CurrentMessage->dwQEvent)
2179 {
2180 if (CurrentMessage->dwQEvent == POSTEVENT_NWE)
2181 {
2182 ExFreePoolWithTag( (PVOID)CurrentMessage->ExtraInfo, TAG_HOOK);
2183 }
2184 }
2185 MsqDestroyMessage(CurrentMessage);
2186 }
2187
2188 /* remove the messages that have not yet been dispatched */
2189 while (!IsListEmpty(&pti->SentMessagesListHead))
2190 {
2191 CurrentEntry = pti->SentMessagesListHead.Flink;
2192 CurrentSentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE, ListEntry);
2193
2194 ERR("Thread Cleanup Sent Messages %p\n",CurrentSentMessage);
2195
2196 /* wake the sender's thread */
2197 if (CurrentSentMessage->pkCompletionEvent != NULL)
2198 {
2199 KeSetEvent(CurrentSentMessage->pkCompletionEvent, IO_NO_INCREMENT, FALSE);
2200 }
2201
2202 if (CurrentSentMessage->HasPackedLParam)
2203 {
2204 if (CurrentSentMessage->Msg.lParam)
2205 ExFreePool((PVOID)CurrentSentMessage->Msg.lParam);
2206 }
2207
2208 /* free the message */
2209 FreeUserMessage(CurrentSentMessage);
2210 }
2211
2212 // Process Trouble Message List
2213 if (!IsListEmpty(&usmList))
2214 {
2215 CurrentEntry = usmList.Flink;
2216 while (CurrentEntry != &usmList)
2217 {
2218 CurrentSentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE, ListEntry);
2219 CurrentEntry = CurrentEntry->Flink;
2220
2221 TRACE("Found troubled messages %p on the list\n",CurrentSentMessage);
2222
2223 if ( pti == CurrentSentMessage->ptiReceiver )
2224 {
2225 if (CurrentSentMessage->HasPackedLParam)
2226 {
2227 if (CurrentSentMessage->Msg.lParam)
2228 ExFreePool((PVOID)CurrentSentMessage->Msg.lParam);
2229 }
2230
2231 /* free the message */
2232 FreeUserMessage(CurrentSentMessage);
2233 }
2234 else if ( pti == CurrentSentMessage->ptiSender ||
2235 pti == CurrentSentMessage->ptiCallBackSender )
2236 {
2237 // Determine whether this message is being processed or not.
2238 if ((CurrentSentMessage->flags & (SMF_RECEIVERBUSY|SMF_RECEIVEDMESSAGE)) != SMF_RECEIVEDMESSAGE)
2239 {
2240 CurrentSentMessage->flags |= SMF_RECEIVERFREE;
2241 }
2242
2243 if (!(CurrentSentMessage->flags & SMF_RECEIVERFREE))
2244 {
2245
2246 if (CurrentSentMessage->HasPackedLParam)
2247 {
2248 if (CurrentSentMessage->Msg.lParam)
2249 ExFreePool((PVOID)CurrentSentMessage->Msg.lParam);
2250 }
2251
2252 /* free the message */
2253 FreeUserMessage(CurrentSentMessage);
2254 }
2255 }
2256 }
2257 }
2258 }
2259
2260 VOID FASTCALL
2261 MsqCleanupMessageQueue(PTHREADINFO pti)
2262 {
2263 PUSER_MESSAGE_QUEUE MessageQueue;
2264
2265 MessageQueue = pti->MessageQueue;
2266 MessageQueue->cThreads--;
2267
2268 if (MessageQueue->cThreads)
2269 {
2270 if (MessageQueue->ptiSysLock == pti) MessageQueue->ptiSysLock = NULL;
2271 }
2272
2273 if (MessageQueue->CursorObject)
2274 {
2275 PCURICON_OBJECT pCursor = MessageQueue->CursorObject;
2276
2277 /* Change to another cursor if we going to dereference current one
2278 Note: we can't use UserSetCursor because it uses current thread
2279 message queue instead of queue given for cleanup */
2280 if (IntGetSysCursorInfo()->CurrentCursorObject == pCursor)
2281 {
2282 HDC hdcScreen;
2283
2284 /* Get the screen DC */
2285 hdcScreen = IntGetScreenDC();
2286 if (hdcScreen)
2287 GreMovePointer(hdcScreen, -1, -1);
2288 IntGetSysCursorInfo()->CurrentCursorObject = NULL;
2289 }
2290
2291 TRACE("DereferenceObject pCursor\n");
2292 UserDereferenceObject(pCursor);
2293 }
2294
2295 if (gpqForeground == MessageQueue)
2296 {
2297 IntSetFocusMessageQueue(NULL);
2298 }
2299 if (gpqForegroundPrev == MessageQueue)
2300 {
2301 gpqForegroundPrev = NULL;
2302 }
2303 if (gpqCursor == MessageQueue)
2304 {
2305 gpqCursor = NULL;
2306 }
2307 }
2308
2309 PUSER_MESSAGE_QUEUE FASTCALL
2310 MsqCreateMessageQueue(PTHREADINFO pti)
2311 {
2312 PUSER_MESSAGE_QUEUE MessageQueue;
2313
2314 MessageQueue = ExAllocatePoolWithTag(NonPagedPool,
2315 sizeof(*MessageQueue),
2316 USERTAG_Q);
2317
2318 if (!MessageQueue)
2319 {
2320 return NULL;
2321 }
2322
2323 RtlZeroMemory(MessageQueue, sizeof(*MessageQueue));
2324 /* hold at least one reference until it'll be destroyed */
2325 IntReferenceMessageQueue(MessageQueue);
2326 /* initialize the queue */
2327 if (!MsqInitializeMessageQueue(pti, MessageQueue))
2328 {
2329 IntDereferenceMessageQueue(MessageQueue);
2330 return NULL;
2331 }
2332
2333 return MessageQueue;
2334 }
2335
2336 VOID FASTCALL
2337 MsqDestroyMessageQueue(_In_ PTHREADINFO pti)
2338 {
2339 PDESKTOP desk;
2340 PUSER_MESSAGE_QUEUE MessageQueue = pti->MessageQueue;
2341
2342 NT_ASSERT(MessageQueue != NULL);
2343 MessageQueue->QF_flags |= QF_INDESTROY;
2344
2345 /* remove the message queue from any desktops */
2346 if ((desk = InterlockedExchangePointer((PVOID*)&MessageQueue->Desktop, 0)))
2347 {
2348 (void)InterlockedExchangePointer((PVOID*)&desk->ActiveMessageQueue, 0);
2349 IntDereferenceMessageQueue(MessageQueue);
2350 }
2351
2352 /* clean it up */
2353 MsqCleanupMessageQueue(pti);
2354
2355 /* decrease the reference counter, if it hits zero, the queue will be freed */
2356 _PRAGMA_WARNING_SUPPRESS(__WARNING_USING_UNINIT_VAR);
2357 IntDereferenceMessageQueue(MessageQueue);
2358 }
2359
2360 LPARAM FASTCALL
2361 MsqSetMessageExtraInfo(LPARAM lParam)
2362 {
2363 LPARAM Ret;
2364 PTHREADINFO pti;
2365 PUSER_MESSAGE_QUEUE MessageQueue;
2366
2367 pti = PsGetCurrentThreadWin32Thread();
2368 MessageQueue = pti->MessageQueue;
2369 if(!MessageQueue)
2370 {
2371 return 0;
2372 }
2373
2374 Ret = MessageQueue->ExtraInfo;
2375 MessageQueue->ExtraInfo = lParam;
2376
2377 return Ret;
2378 }
2379
2380 LPARAM FASTCALL
2381 MsqGetMessageExtraInfo(VOID)
2382 {
2383 PTHREADINFO pti;
2384 PUSER_MESSAGE_QUEUE MessageQueue;
2385
2386 pti = PsGetCurrentThreadWin32Thread();
2387 MessageQueue = pti->MessageQueue;
2388 if(!MessageQueue)
2389 {
2390 return 0;
2391 }
2392
2393 return MessageQueue->ExtraInfo;
2394 }
2395
2396 // ReplyMessage is called by the thread receiving the window message.
2397 BOOL FASTCALL
2398 co_MsqReplyMessage( LRESULT lResult )
2399 {
2400 PUSER_SENT_MESSAGE Message;
2401 PTHREADINFO pti;
2402
2403 pti = PsGetCurrentThreadWin32Thread();
2404 Message = pti->pusmCurrent;
2405
2406 if (!Message) return FALSE;
2407
2408 if (Message->QS_Flags & QS_SMRESULT) return FALSE;
2409
2410 // SendMessageXxx || Callback msg and not a notify msg
2411 if (Message->ptiSender || Message->CompletionCallback)
2412 {
2413 Message->lResult = lResult;
2414 Message->QS_Flags |= QS_SMRESULT;
2415 // See co_MsqDispatchOneSentMessage, change bits already accounted for and cleared and this msg is going away..
2416 }
2417 return TRUE;
2418 }
2419
2420 HWND FASTCALL
2421 MsqSetStateWindow(PTHREADINFO pti, ULONG Type, HWND hWnd)
2422 {
2423 HWND Prev;
2424 PUSER_MESSAGE_QUEUE MessageQueue;
2425
2426 MessageQueue = pti->MessageQueue;
2427
2428 switch(Type)
2429 {
2430 case MSQ_STATE_CAPTURE:
2431 Prev = MessageQueue->spwndCapture ? UserHMGetHandle(MessageQueue->spwndCapture) : 0;
2432 MessageQueue->spwndCapture = ValidateHwndNoErr(hWnd);
2433 return Prev;
2434 case MSQ_STATE_ACTIVE:
2435 Prev = MessageQueue->spwndActive ? UserHMGetHandle(MessageQueue->spwndActive) : 0;
2436 MessageQueue->spwndActive = ValidateHwndNoErr(hWnd);
2437 return Prev;
2438 case MSQ_STATE_FOCUS:
2439 Prev = MessageQueue->spwndFocus ? UserHMGetHandle(MessageQueue->spwndFocus) : 0;
2440 MessageQueue->spwndFocus = ValidateHwndNoErr(hWnd);
2441 return Prev;
2442 case MSQ_STATE_MENUOWNER:
2443 Prev = MessageQueue->MenuOwner;
2444 MessageQueue->MenuOwner = hWnd;
2445 return Prev;
2446 case MSQ_STATE_MOVESIZE:
2447 Prev = MessageQueue->MoveSize;
2448 MessageQueue->MoveSize = hWnd;
2449 return Prev;
2450 case MSQ_STATE_CARET:
2451 Prev = MessageQueue->CaretInfo.hWnd;
2452 MessageQueue->CaretInfo.hWnd = hWnd;
2453 return Prev;
2454 }
2455
2456 return NULL;
2457 }
2458
2459 SHORT
2460 APIENTRY
2461 NtUserGetKeyState(INT key)
2462 {
2463 DWORD Ret;
2464
2465 UserEnterShared();
2466
2467 Ret = UserGetKeyState(key);
2468
2469 UserLeave();
2470
2471 return (SHORT)Ret;
2472 }
2473
2474
2475 DWORD
2476 APIENTRY
2477 NtUserGetKeyboardState(LPBYTE lpKeyState)
2478 {
2479 DWORD i, ret = TRUE;
2480 PTHREADINFO pti;
2481 PUSER_MESSAGE_QUEUE MessageQueue;
2482
2483 UserEnterShared();
2484
2485 pti = PsGetCurrentThreadWin32Thread();
2486 MessageQueue = pti->MessageQueue;
2487
2488 _SEH2_TRY
2489 {
2490 /* Probe and copy key state to an array */
2491 ProbeForWrite(lpKeyState, 256 * sizeof(BYTE), 1);
2492 for (i = 0; i < 256; ++i)
2493 {
2494 lpKeyState[i] = 0;
2495 if (IS_KEY_DOWN(MessageQueue->afKeyState, i))
2496 lpKeyState[i] |= KS_DOWN_BIT;
2497 if (IS_KEY_LOCKED(MessageQueue->afKeyState, i))
2498 lpKeyState[i] |= KS_LOCK_BIT;
2499 }
2500 }
2501 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2502 {
2503 SetLastNtError(_SEH2_GetExceptionCode());
2504 ret = FALSE;
2505 }
2506 _SEH2_END;
2507
2508 UserLeave();
2509
2510 return ret;
2511 }
2512
2513 BOOL
2514 APIENTRY
2515 NtUserSetKeyboardState(LPBYTE pKeyState)
2516 {
2517 UINT i;
2518 BOOL bRet = TRUE;
2519 PTHREADINFO pti;
2520 PUSER_MESSAGE_QUEUE MessageQueue;
2521
2522 UserEnterExclusive();
2523
2524 pti = PsGetCurrentThreadWin32Thread();
2525 MessageQueue = pti->MessageQueue;
2526
2527 _SEH2_TRY
2528 {
2529 ProbeForRead(pKeyState, 256 * sizeof(BYTE), 1);
2530 for (i = 0; i < 256; ++i)
2531 {
2532 SET_KEY_DOWN(MessageQueue->afKeyState, i, pKeyState[i] & KS_DOWN_BIT);
2533 SET_KEY_LOCKED(MessageQueue->afKeyState, i, pKeyState[i] & KS_LOCK_BIT);
2534 }
2535 }
2536 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2537 {
2538 SetLastNtError(_SEH2_GetExceptionCode());
2539 bRet = FALSE;
2540 }
2541 _SEH2_END;
2542
2543 UserLeave();
2544
2545 return bRet;
2546 }
2547
2548 /* EOF */