How Windows 3.11 Processed Mouse Input System Queues

In Microsoft Windows 3.11, mouse input processing relied on a 16-bit cooperative multitasking architecture where hardware interrupts, low-level drivers, and a centralized system message queue worked together to route user actions. Physical movements and button clicks were initially captured by hardware drivers, converted into low-level events, and deposited into a single, global System Message Queue. The Windows USER.EXE subsystem then inspected these entries, performed spatial hit-testing to identify the target window, translated the raw data into standard window messages (such as WM_MOUSEMOVE or WM_LBUTTONDOWN), and dispatched them to the appropriate application's message queue.

When a user moved the mouse or pressed a button, the physical device signaled a hardware interrupt (typically IRQ 12 for PS/2 mice or IRQ 4/3 for serial mice). The mouse driver (MOUSE.DRV) intercepted this interrupt and processed the raw delta changes in position and button states. The driver then invoked an internal operating system function—typically mouse_event within USER.EXE—to hand off the hardware-level data to the Windows environment.

Windows 3.11 placed these incoming events directly into the System Message Queue (often called the raw input queue or SYSQ). Unlike modern versions of Windows that provide completely independent input queues per thread, Windows 3.11 maintained this single, shared system queue for all incoming hardware input, including both mouse and keyboard events. The entries in this queue contained basic information: the timestamp of the event, the raw screen coordinates, and the state of the mouse buttons.

To distribute input to software, Windows 3.11 relied on the cooperative message loop implemented in running programs. Applications continually called GetMessage() or PeekMessage() to retrieve pending events. When an application called one of these functions, the operating system checked the System Message Queue to process the next raw input event.

During this retrieval phase, USER.EXE performed hit-testing using an internal routine similar to WindowFromPoint(). It evaluated the current screen coordinates of the mouse against the coordinates of all visible, enabled windows and their child controls (z-order from top to bottom) to identify which window owned that specific screen space. If a window had previously captured the mouse using SetCapture(), the input was redirected exclusively to that window regardless of cursor position.

Once the destination window was determined, the operating system converted the raw screen coordinates into client-area coordinates (relative to the upper-left corner of the target window's client space). It then generated the appropriate high-level message—such as WM_LBUTTONDOWN, WM_RBUTTONUP, or WM_MOUSEMOVE—along with flags indicating whether modifier keys like Shift or Control were active.

Finally, the generated message was placed into the local message queue of the specific application that owned the target window. The application's GetMessage() call returned the message structure, and the application subsequently invoked DispatchMessage() to execute the destination window's callback function (WindowProc), completing the input lifecycle. Because of this single-queue architecture, if a foreground application hung or entered an unyielding loop, processing of the System Message Queue stopped, freezing mouse input across the entire operating system.