Skip to content

Mouse Protocol Handlers

opencode-agent[bot] edited this page May 11, 2026 · 1 revision

Mouse Protocol Handlers

Pluggable protocol decoders that convert raw PS/2 mouse packet bytes into PointerEvent objects.

Overview

Mouse protocol handlers decode the varying byte sequences emitted by different PS/2 mouse types (standard 3-button, wheel mice, etc.) into a consistent PointerEvent representation. The MouseProtocolHandlerManager acts as a plugin-based factory, while individual handlers implement the MouseProtocolHandler interface to parse device-specific packets.

Key Components

Class File Responsibility
MouseProtocolHandler core/src/driver/org/jnode/driver/input/MouseProtocolHandler.java Interface defining decode contract
LogitechProtocol core/src/driver/org/jnode/driver/input/LogitechProtocol.java 3-byte Logitech protocol implementation
LogitechWheelMouseProtocol core/src/driver/org/jnode/driver/input/LogitechWheelMouseProtocol.java 4-byte wheel mouse extension
MouseProtocolHandlerManager core/src/driver/org/jnode/driver/input/MouseProtocolHandlerManager.java Plugin-based handler registry
MouseInterpreter core/src/driver/org/jnode/driver/input/MouseInterpreter.java Probes mouse, selects handler, assembles packets
PointerEvent core/src/driver/org/jnode/driver/input/PointerEvent.java The decoded event output
InputPlugin core/src/driver/org/jnode/driver/input/InputPlugin.java Plugin entry point, binds manager to InitialNaming

How It Works

1. Plugin Registration

Handlers declare themselves via the org.jnode.driver.input.mouse-protocol-handlers extension point in their plugin descriptor:

<extension-point id="mouse-protocol-handlers"/>
<extension point="org.jnode.driver.input.mouse-protocol-handlers">
  <handler name="Logitech Mouse" class="org.jnode.driver.input.LogitechProtocol"/>
  <handler name="Logitech Wheel Mouse" class="org.jnode.driver.input.LogitechWheelMouseProtocol"/>
</extension>

2. Protocol Handler Interface

public interface MouseProtocolHandler {
    String getName();
    boolean supportsId(int id);
    int getPacketSize();
    PointerEvent buildEvent(byte[] data);
}

Each handler reports:

  • Whether it handles a given device ID (from getPointerId())
  • The packet size in bytes (3 for standard, 4 for wheel)
  • The decoded event built from the raw bytes

3. Mouse Probing and Handler Selection

MouseInterpreter.probe() performs device identification:

// Reset mouse to get base ID
d.initPointer(true);
pointerId = d.getPointerId();

// Attempt wheel mouse detection sequence
d.setRate(200);
d.setRate(100);
d.setRate(80);
pointerId = d.getPointerId(); // ID changes to 3 on wheel mice

// Select matching handler
for (MouseProtocolHandler p : mgr.protocolHandlers()) {
    if (p.supportsId(pointerId)) {
        this.protocol = p;
        break;
    }
}

4. Packet Assembly

MouseInterpreter.handleScancode() accumulates bytes until a full packet is received, then delegates to the handler:

public synchronized PointerEvent handleScancode(int scancode) {
    data[pos++] = (byte) (scancode & 0xff);
    pos %= data.length;
    if (pos != 0) {
        return null; // Incomplete packet
    }
    return protocol.buildEvent(data);
}

5. Logitech Protocol Decoding

LogitechProtocol.buildEvent() decodes the 3-byte PS/2 mouse packet:

Byte 0: Y overflow, X overflow, Y sign, X sign, 1, Middle, Right, Left
Byte 1: X movement (signed, twos complement applied via sign bit)
Byte 2: Y movement (signed, twos complement applied via sign bit)
public PointerEvent buildEvent(byte[] data) {
    final int d0 = data[0] & 0xFF;
    final int d1 = data[1] & 0xFF;
    final int d2 = data[2] & 0xFF;

    // Discard packets with overflow indicators
    if ((d0 & (0x40 | 0x80)) != 0)
        return null;

    final int buttons = d0 & 0x07;
    final int x = (d1 != 0) ? d1 - ((d0 & 0x10) << 4) : 0;
    final int y = (d2 != 0) ? ((d0 & 0x20) << 3) - d2 : 0;

    return new PointerEvent(buttons, x, y, PointerEvent.RELATIVE);
}

6. Wheel Mouse Extension

LogitechWheelMouseProtocol extends the base protocol with a 4th byte for wheel data:

public PointerEvent buildEvent(byte[] data) {
    PointerEvent e = super.buildEvent(data);
    if (e == null) return null;

    int z = data[3];
    if (z == 127) z = -1; // Center position maps to negative
    return new PointerEvent(e.getButtons(), e.getX(), e.getY(), z, e.isAbsolute());
}

7. PointerEvent Output

The decoded event carries button state and X/Y/Z (wheel) values:

PointerEvent({LMR}) x y z REL

Button bits: BUTTON_LEFT=1, BUTTON_MIDDLE=4, BUTTON_RIGHT=2.

Gotchas

  • ID persistence anomaly: After wheel mouse detection, pointerId remains 3 on subsequent probes instead of resetting to 0. See MouseInterpreter.java:65 TODO comment.
  • Overflow discard: Packets with X or Y overflow bits set are silently dropped — useful for detecting protocol mismatch.
  • Null returns: buildEvent() returns null on invalid packets, which MouseInterpreter propagates as null (no event delivered).
  • Plugin initialization order: MouseProtocolHandlerManager requires plugins to be started before handlers are registered via extension points.

Clone this wiki locally