BOOL UserSetCursorPos( INT x, INT y, DWORD flags, ULONG_PTR dwExtraInfo, BOOL Hook) { PWND DesktopWindow; PSYSTEM_CURSORINFO CurInfo; MSG Msg; RECTL rcClip; POINT pt; if(!(DesktopWindow = UserGetDesktopWindow())) { return FALSE; } CurInfo = IntGetSysCursorInfo(); /* Clip cursor position */ if (!CurInfo->bClipped) rcClip = DesktopWindow->rcClient; else rcClip = CurInfo->rcClip; if(x >= rcClip.right) x = rcClip.right - 1; if(x < rcClip.left) x = rcClip.left; if(y >= rcClip.bottom) y = rcClip.bottom - 1; if(y < rcClip.top) y = rcClip.top; pt.x = x; pt.y = y; /* 1. Generate a mouse move message, this sets the htEx and Track Window too. */ Msg.message = WM_MOUSEMOVE; Msg.wParam = UserGetMouseButtonsState(); Msg.lParam = MAKELPARAM(x, y); Msg.pt = pt; co_MsqInsertMouseMessage(&Msg, flags, dwExtraInfo, Hook); /* 2. Store the new cursor position */ gpsi->ptCursor = pt; return TRUE; }
NTSTATUS FASTCALL UserAttachThreadInput(PTHREADINFO ptiFrom, PTHREADINFO ptiTo, BOOL fAttach) { MSG msg; PATTACHINFO pai; /* Can not be the same thread. */ if (ptiFrom == ptiTo) return STATUS_INVALID_PARAMETER; /* Do not attach to system threads or between different desktops. */ if (ptiFrom->TIF_flags & TIF_DONTATTACHQUEUE || ptiTo->TIF_flags & TIF_DONTATTACHQUEUE || ptiFrom->rpdesk != ptiTo->rpdesk) return STATUS_ACCESS_DENIED; /* MSDN Note: Keyboard and mouse events received by both threads are processed by the thread specified by the idAttachTo. */ /* If Attach set, allocate and link. */ if (fAttach) { pai = ExAllocatePoolWithTag(PagedPool, sizeof(ATTACHINFO), USERTAG_ATTACHINFO); if (!pai) return STATUS_NO_MEMORY; pai->paiNext = gpai; pai->pti1 = ptiFrom; pai->pti2 = ptiTo; gpai = pai; paiCount++; ERR("Attach Allocated! ptiFrom 0x%p ptiTo 0x%p paiCount %d\n",ptiFrom,ptiTo,paiCount); if (ptiTo->MessageQueue != ptiFrom->MessageQueue) { ptiTo->MessageQueue->iCursorLevel -= ptiFrom->iCursorLevel; // FIXME: conditions? if (ptiTo->MessageQueue == gpqForeground) { ERR("ptiTo is Foreground\n"); } else { ERR("ptiTo NOT Foreground\n"); } if (ptiFrom->MessageQueue == gpqForeground) { ERR("ptiFrom is Foreground\n"); ptiTo->MessageQueue->spwndActive = ptiFrom->MessageQueue->spwndActive; ptiTo->MessageQueue->spwndFocus = ptiFrom->MessageQueue->spwndFocus; ptiTo->MessageQueue->CursorObject = ptiFrom->MessageQueue->CursorObject; ptiTo->MessageQueue->spwndCapture = ptiFrom->MessageQueue->spwndCapture; ptiTo->MessageQueue->QF_flags ^= ((ptiTo->MessageQueue->QF_flags ^ ptiFrom->MessageQueue->QF_flags) & QF_CAPTURELOCKED); ptiTo->MessageQueue->CaretInfo = ptiFrom->MessageQueue->CaretInfo; IntSetFocusMessageQueue(NULL); IntSetFocusMessageQueue(ptiTo->MessageQueue); gptiForeground = ptiTo; } else { ERR("ptiFrom NOT Foreground\n"); } MsqDestroyMessageQueue(ptiFrom); ptiFrom->MessageQueue = ptiTo->MessageQueue; ptiFrom->MessageQueue->cThreads++; ERR("ptiTo S Share count %d\n", ptiFrom->MessageQueue->cThreads); IntReferenceMessageQueue(ptiTo->MessageQueue); } else { ERR("Attach Threads are already associated!\n"); } } else /* If clear, unlink and free it. */ { BOOL Hit = FALSE; PATTACHINFO *ppai; if (!gpai) return STATUS_INVALID_PARAMETER; /* Search list and free if found or return false. */ ppai = &gpai; while (*ppai != NULL) { if ( (*ppai)->pti2 == ptiTo && (*ppai)->pti1 == ptiFrom ) { pai = *ppai; /* Remove it from the list */ *ppai = (*ppai)->paiNext; ExFreePoolWithTag(pai, USERTAG_ATTACHINFO); paiCount--; Hit = TRUE; break; } ppai = &((*ppai)->paiNext); } if (!Hit) return STATUS_INVALID_PARAMETER; ERR("Attach Free! ptiFrom 0x%p ptiTo 0x%p paiCount %d\n",ptiFrom,ptiTo,paiCount); if (ptiTo->MessageQueue == ptiFrom->MessageQueue) { if (gptiForeground == ptiFrom) { ERR("ptiTo is now pti FG.\n"); // MessageQueue foreground is set so switch threads. gptiForeground = ptiTo; } ptiTo->MessageQueue->cThreads--; ERR("ptiTo E Share count %d\n", ptiTo->MessageQueue->cThreads); ASSERT(ptiTo->MessageQueue->cThreads >= 1); IntDereferenceMessageQueue(ptiTo->MessageQueue); ptiFrom->MessageQueue = MsqCreateMessageQueue(ptiFrom); ptiTo->MessageQueue->iCursorLevel -= ptiFrom->iCursorLevel; } else { ERR("Detaching Threads are not associated!\n"); } } /* Note that key state, which can be ascertained by calls to the GetKeyState or GetKeyboardState function, is reset after a call to AttachThreadInput. ATM which one? */ RtlCopyMemory(ptiTo->MessageQueue->afKeyState, gafAsyncKeyState, sizeof(gafAsyncKeyState)); /* Generate mouse move message */ msg.message = WM_MOUSEMOVE; msg.wParam = UserGetMouseButtonsState(); msg.lParam = MAKELPARAM(gpsi->ptCursor.x, gpsi->ptCursor.y); msg.pt = gpsi->ptCursor; co_MsqInsertMouseMessage(&msg, 0, 0, TRUE); return STATUS_SUCCESS; }