The Pedigree Project 0.1
Ps2MousePacket.cc
1/*
2 * Copyright (c) 2026, Pedigree Developers
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted.
6 */
7
8#include "Ps2MousePacket.h"
9
10namespace {
11constexpr uint8_t StatusLeftButton = 1 << 0;
12constexpr uint8_t StatusRightButton = 1 << 1;
13constexpr uint8_t StatusMiddleButton = 1 << 2;
14constexpr uint8_t StatusAlwaysOne = 1 << 3;
15constexpr uint8_t StatusXSign = 1 << 4;
16constexpr uint8_t StatusYSign = 1 << 5;
17constexpr uint8_t StatusXOverflow = 1 << 6;
18constexpr uint8_t StatusYOverflow = 1 << 7;
19
20ssize_t decodeMovement(uint8_t movement, uint8_t status, uint8_t signBit) {
21 uint16_t value = movement;
22 if (status & signBit) {
23 value |= 0x100;
24 }
25
26 if (value & 0x100) {
27 return static_cast<ssize_t>(value) - 0x200;
28 }
29 return static_cast<ssize_t>(value);
30}
31} // namespace
32
33Ps2MousePacketDecoder::Ps2MousePacketDecoder() : m_Buffer(), m_BufferIndex(0) {}
34
35void Ps2MousePacketDecoder::reset() {
36 m_BufferIndex = 0;
37}
38
39bool Ps2MousePacketDecoder::feed(uint8_t byte, Ps2MousePacket& packet) {
40 // Bit 3 is permanently set in the first byte of a standard PS/2 packet.
41 // Discarding until it is seen lets the stream recover from stray bytes.
42 if (m_BufferIndex == 0 && !(byte & StatusAlwaysOne)) {
43 return false;
44 }
45
46 m_Buffer[m_BufferIndex++] = byte;
47 if (m_BufferIndex != 3) {
48 return false;
49 }
50
51 const uint8_t status = m_Buffer[0];
52 const bool xOverflow = status & StatusXOverflow;
53 const bool yOverflow = status & StatusYOverflow;
54
55 packet.relativeX = xOverflow ? 0 : decodeMovement(m_Buffer[1], status, StatusXSign);
56 packet.relativeY = yOverflow ? 0 : decodeMovement(m_Buffer[2], status, StatusYSign);
57 packet.overflow = xOverflow || yOverflow;
58
59 // InputManager numbers buttons left, middle, right. The PS/2 status byte
60 // numbers its middle and right buttons in the opposite order.
61 packet.buttons = 0;
62 if (status & StatusLeftButton) {
63 packet.buttons |= 1 << 0;
64 }
65 if (status & StatusMiddleButton) {
66 packet.buttons |= 1 << 1;
67 }
68 if (status & StatusRightButton) {
69 packet.buttons |= 1 << 2;
70 }
71
72 m_BufferIndex = 0;
73 return true;
74}
bool feed(uint8_t byte, Ps2MousePacket &packet)