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.