* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Win32k subsystem
* PURPOSE: General input functions
- * FILE: subsystems/win32/win32k/ntuser/input.c
+ * FILE: win32ss/user/ntuser/input.c
* PROGRAMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
* Rafal Harabien (rafalh@reactos.org)
*/
InitializeObjectAttributes(&ObjectAttributes,
&DeviceName,
- 0,
+ OBJ_KERNEL_HANDLE,
NULL,
NULL);
* Reads data from input devices and supports win32 timers
*/
VOID NTAPI
-RawInputThreadMain()
+RawInputThreadMain(VOID)
{
NTSTATUS MouStatus = STATUS_UNSUCCESSFUL, KbdStatus = STATUS_UNSUCCESSFUL, Status;
IO_STATUS_BLOCK MouIosb, KbdIosb;
PFILE_OBJECT pKbdDevice = NULL, pMouDevice = NULL;
LARGE_INTEGER ByteOffset;
//LARGE_INTEGER WaitTimeout;
- PVOID WaitObjects[3], pSignaledObject = NULL;
- ULONG cWaitObjects = 0, cMaxWaitObjects = 1;
+ PVOID WaitObjects[4], pSignaledObject = NULL;
+ KWAIT_BLOCK WaitBlockArray[RTL_NUMBER_OF(WaitObjects)];
+ ULONG cWaitObjects = 0, cMaxWaitObjects = 2;
MOUSE_INPUT_DATA MouseInput;
KEYBOARD_INPUT_DATA KeyInput;
+ PVOID ShutdownEvent;
ByteOffset.QuadPart = (LONGLONG)0;
//WaitTimeout.QuadPart = (LONGLONG)(-10000000);
StartTheTimers();
UserLeave();
- for(;;)
+ NT_ASSERT(ghMouseDevice == NULL);
+ NT_ASSERT(ghKeyboardDevice == NULL);
+
+ PoRequestShutdownEvent(&ShutdownEvent);
+ for (;;)
{
if (!ghMouseDevice)
{
/* Reset WaitHandles array */
cWaitObjects = 0;
+ WaitObjects[cWaitObjects++] = ShutdownEvent;
WaitObjects[cWaitObjects++] = MasterTimer;
if (ghMouseDevice)
KernelMode,
TRUE,
NULL,//&WaitTimeout,
- NULL);
+ WaitBlockArray);
if ((Status >= STATUS_WAIT_0) &&
(Status < (STATUS_WAIT_0 + (LONG)cWaitObjects)))
pSignaledObject = WaitObjects[Status - STATUS_WAIT_0];
/* Check if it is mouse or keyboard and update status */
- if (pSignaledObject == &pMouDevice->Event)
+ if ((MouStatus == STATUS_PENDING) &&
+ (pSignaledObject == &pMouDevice->Event))
+ {
MouStatus = MouIosb.Status;
- else if (pSignaledObject == &pKbdDevice->Event)
+ }
+ else if ((KbdStatus == STATUS_PENDING) &&
+ (pSignaledObject == &pKbdDevice->Event))
+ {
KbdStatus = KbdIosb.Status;
+ }
else if (pSignaledObject == MasterTimer)
{
ProcessTimers();
}
+ else if (pSignaledObject == ShutdownEvent)
+ {
+ break;
+ }
else ASSERT(FALSE);
}
}
else if (KbdStatus != STATUS_PENDING)
ERR("Failed to read from keyboard: %x.\n", KbdStatus);
}
+
+ if (ghMouseDevice)
+ {
+ (void)ZwCancelIoFile(ghMouseDevice, &MouIosb);
+ ObCloseHandle(ghMouseDevice, KernelMode);
+ ObDereferenceObject(pMouDevice);
+ ghMouseDevice = NULL;
+ }
+
+ if (ghKeyboardDevice)
+ {
+ (void)ZwCancelIoFile(ghKeyboardDevice, &KbdIosb);
+ ObCloseHandle(ghKeyboardDevice, KernelMode);
+ ObDereferenceObject(pKbdDevice);
+ ghKeyboardDevice = NULL;
+ }
+
ERR("Raw Input Thread Exit!\n");
}
* CreateSystemThreads
*
* Called form dedicated thread in CSRSS. RIT is started in context of this
- * thread because it needs valid Win32 process with TEB initialized
+ * thread because it needs valid Win32 process with TEB initialized.
*/
DWORD NTAPI
CreateSystemThreads(UINT Type)
return ret;
}
-PTHREADINFO FASTCALL
-IsThreadAttach(PTHREADINFO ptiTo)
+BOOL
+FASTCALL
+IsRemoveAttachThread(PTHREADINFO pti)
{
+ NTSTATUS Status;
PATTACHINFO pai;
+ BOOL Ret = TRUE;
+ PTHREADINFO ptiFrom = NULL, ptiTo = NULL;
- if (!gpai) return NULL;
-
- pai = gpai;
do
{
- if (pai->pti2 == ptiTo) break;
- pai = pai->paiNext;
- } while (pai);
+ if (!gpai) return TRUE;
+
+ pai = gpai; // Bottom of the list.
- if (!pai) return NULL;
+ do
+ {
+ if (pai->pti2 == pti)
+ {
+ ptiFrom = pai->pti1;
+ ptiTo = pti;
+ break;
+ }
+ if (pai->pti1 == pti)
+ {
+ ptiFrom = pti;
+ ptiTo = pai->pti2;
+ break;
+ }
+ pai = pai->paiNext;
- // Return ptiFrom.
- return pai->pti1;
+ } while (pai);
+
+ if (!pai && !ptiFrom && !ptiTo) break;
+
+ Status = UserAttachThreadInput(ptiFrom, ptiTo, FALSE);
+ if (!NT_SUCCESS(Status)) Ret = FALSE;
+
+ } while (Ret);
+
+ return Ret;
}
NTSTATUS FASTCALL
{
MSG msg;
PATTACHINFO pai;
+ PCURICON_OBJECT CurIcon;
/* Can not be the same thread. */
if (ptiFrom == ptiTo) return STATUS_INVALID_PARAMETER;
paiCount++;
ERR("Attach Allocated! ptiFrom 0x%p ptiTo 0x%p paiCount %d\n",ptiFrom,ptiTo,paiCount);
- if (ptiTo->MessageQueue == ptiFrom->MessageQueue)
+ if (ptiTo->MessageQueue != ptiFrom->MessageQueue)
{
- ERR("Attach Threads are already associated!\n");
- }
- ptiTo->MessageQueue->iCursorLevel -= ptiFrom->iCursorLevel;
+ ptiTo->MessageQueue->iCursorLevel -= ptiFrom->iCursorLevel;
+
+ if (ptiFrom->MessageQueue == gpqForeground)
+ {
+ ERR("ptiFrom is Foreground\n");
+ ptiTo->MessageQueue->spwndActive = ptiFrom->MessageQueue->spwndActive;
+ ptiTo->MessageQueue->spwndFocus = ptiFrom->MessageQueue->spwndFocus;
+ ptiTo->MessageQueue->spwndCapture = ptiFrom->MessageQueue->spwndCapture;
+ ptiTo->MessageQueue->QF_flags ^= ((ptiTo->MessageQueue->QF_flags ^ ptiFrom->MessageQueue->QF_flags) & QF_CAPTURELOCKED);
+ RtlCopyMemory(ptiTo->MessageQueue->CaretInfo,
+ ptiFrom->MessageQueue->CaretInfo,
+ sizeof(*ptiTo->MessageQueue->CaretInfo));
+ IntSetFocusMessageQueue(NULL);
+ IntSetFocusMessageQueue(ptiTo->MessageQueue);
+ gptiForeground = ptiTo;
+ }
+ else
+ {
+ ERR("ptiFrom NOT Foreground\n");
+ if ( ptiTo->MessageQueue->spwndActive == 0 )
+ ptiTo->MessageQueue->spwndActive = ptiFrom->MessageQueue->spwndActive;
+ if ( ptiTo->MessageQueue->spwndFocus == 0 )
+ ptiTo->MessageQueue->spwndFocus = ptiFrom->MessageQueue->spwndFocus;
+ }
- /* Keep the original queue in pqAttach (ie do not trash it in a second attachment) */
- if (ptiFrom->pqAttach == NULL)
- ptiFrom->pqAttach = ptiFrom->MessageQueue;
- ptiFrom->MessageQueue = ptiTo->MessageQueue;
+ CurIcon = ptiFrom->MessageQueue->CursorObject;
- ptiFrom->MessageQueue->cThreads++;
- ERR("ptiTo S Share count %lu\n", ptiFrom->MessageQueue->cThreads);
+ MsqDestroyMessageQueue(ptiFrom);
- // FIXME: conditions?
- if (ptiFrom->pqAttach == gpqForeground)
- {
- ERR("ptiFrom is Foreground\n");
- ptiFrom->MessageQueue->spwndActive = ptiFrom->pqAttach->spwndActive;
- ptiFrom->MessageQueue->spwndFocus = ptiFrom->pqAttach->spwndFocus;
- ptiFrom->MessageQueue->CursorObject = ptiFrom->pqAttach->CursorObject;
- ptiFrom->MessageQueue->spwndCapture = ptiFrom->pqAttach->spwndCapture;
- ptiFrom->MessageQueue->QF_flags ^= ((ptiFrom->MessageQueue->QF_flags ^ ptiFrom->pqAttach->QF_flags) & QF_CAPTURELOCKED);
- ptiFrom->MessageQueue->CaretInfo = ptiFrom->pqAttach->CaretInfo;
- }
- else
- {
- ERR("ptiFrom NOT Foreground\n");
- }
- if (ptiTo->MessageQueue == gpqForeground)
- {
- ERR("ptiTo is Foreground\n");
+ if (CurIcon)
+ {
+ // Could be global. Keep it above the water line!
+ UserReferenceObject(CurIcon);
+ }
+
+ if (CurIcon && UserObjectInDestroy(UserHMGetHandle(CurIcon)))
+ {
+ UserDereferenceObject(CurIcon);
+ CurIcon = NULL;
+ }
+
+ ptiFrom->MessageQueue = ptiTo->MessageQueue;
+
+ // Pass cursor From if To is null. Pass test_SetCursor parent_id == current pti ID.
+ if (CurIcon && ptiTo->MessageQueue->CursorObject == NULL)
+ {
+ ERR("ptiTo receiving ptiFrom Cursor\n");
+ ptiTo->MessageQueue->CursorObject = CurIcon;
+ }
+
+ ptiFrom->MessageQueue->cThreads++;
+ ERR("ptiTo S Share count %u\n", ptiFrom->MessageQueue->cThreads);
+
+ IntReferenceMessageQueue(ptiTo->MessageQueue);
}
else
{
- ERR("ptiTo NOT Foreground\n");
+ ERR("Attach Threads are already associated!\n");
}
}
else /* If clear, unlink and free it. */
if (!Hit) return STATUS_INVALID_PARAMETER;
- ASSERT(ptiFrom->pqAttach);
-
ERR("Attach Free! ptiFrom 0x%p ptiTo 0x%p paiCount %d\n",ptiFrom,ptiTo,paiCount);
- /* Search list and check if the thread is attached one more time */
- pai = gpai;
- while(pai)
+ if (ptiTo->MessageQueue == ptiFrom->MessageQueue)
{
- /* If the thread is attached again , we are done */
- if (pai->pti1 == ptiFrom)
- {
- ptiFrom->MessageQueue->cThreads--;
- ERR("ptiTo L Share count %lu\n", ptiFrom->MessageQueue->cThreads);
- /* Use the message queue of the last attachment */
- ptiFrom->MessageQueue = pai->pti2->MessageQueue;
- ptiFrom->MessageQueue->CursorObject = NULL;
- ptiFrom->MessageQueue->spwndActive = NULL;
- ptiFrom->MessageQueue->spwndFocus = NULL;
- ptiFrom->MessageQueue->spwndCapture = NULL;
- return STATUS_SUCCESS;
- }
- pai = pai->paiNext;
- }
+ PWND spwndActive = ptiTo->MessageQueue->spwndActive;
+ PWND spwndFocus = ptiTo->MessageQueue->spwndFocus;
- ptiFrom->MessageQueue->cThreads--;
- ERR("ptiTo E Share count %lu\n", ptiFrom->MessageQueue->cThreads);
- ptiFrom->MessageQueue = ptiFrom->pqAttach;
- // FIXME: conditions?
- ptiFrom->MessageQueue->CursorObject = NULL;
- ptiFrom->MessageQueue->spwndActive = NULL;
- ptiFrom->MessageQueue->spwndFocus = NULL;
- ptiFrom->MessageQueue->spwndCapture = NULL;
- ptiFrom->pqAttach = NULL;
- ptiTo->MessageQueue->iCursorLevel -= ptiFrom->iCursorLevel;
+ 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 %u\n", ptiTo->MessageQueue->cThreads);
+ ASSERT(ptiTo->MessageQueue->cThreads >= 1);
+
+ IntDereferenceMessageQueue(ptiTo->MessageQueue);
+
+ ptiFrom->MessageQueue = MsqCreateMessageQueue(ptiFrom);
+
+ if (spwndActive)
+ {
+ if (spwndActive->head.pti == ptiFrom)
+ {
+ ptiFrom->MessageQueue->spwndActive = spwndActive;
+ ptiTo->MessageQueue->spwndActive = 0;
+ }
+ }
+ if (spwndFocus)
+ {
+ if (spwndFocus->head.pti == ptiFrom)
+ {
+ ptiFrom->MessageQueue->spwndFocus = spwndFocus;
+ ptiTo->MessageQueue->spwndFocus = 0;
+ }
+ }
+ 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.
*/
RtlCopyMemory(ptiTo->MessageQueue->afKeyState, gafAsyncKeyState, sizeof(gafAsyncKeyState));
+ ptiTo->MessageQueue->msgDblClk.message = 0;
+
/* Generate mouse move message */
msg.message = WM_MOUSEMOVE;
msg.wParam = UserGetMouseButtonsState();
return STATUS_SUCCESS;
}
+BOOL
+APIENTRY
+NtUserAttachThreadInput(
+ IN DWORD idAttach,
+ IN DWORD idAttachTo,
+ IN BOOL fAttach)
+{
+ NTSTATUS Status;
+ PTHREADINFO pti, ptiTo;
+ BOOL Ret = FALSE;
+
+ UserEnterExclusive();
+ TRACE("Enter NtUserAttachThreadInput %s\n",(fAttach ? "TRUE" : "FALSE" ));
+
+ pti = IntTID2PTI((HANDLE)idAttach);
+ ptiTo = IntTID2PTI((HANDLE)idAttachTo);
+
+ if ( !pti || !ptiTo )
+ {
+ TRACE("AttachThreadInput pti or ptiTo NULL.\n");
+ EngSetLastError(ERROR_INVALID_PARAMETER);
+ goto Exit;
+ }
+
+ Status = UserAttachThreadInput( pti, ptiTo, fAttach);
+ if (!NT_SUCCESS(Status))
+ {
+ TRACE("AttachThreadInput Error Status 0x%x. \n",Status);
+ EngSetLastError(RtlNtStatusToDosError(Status));
+ }
+ else Ret = TRUE;
+
+Exit:
+ TRACE("Leave NtUserAttachThreadInput, ret=%d\n",Ret);
+ UserLeave();
+ return Ret;
+}
+
/*
* NtUserSendInput
*