# Mouse Report Parsing for Combo KB+Touchpad ## Context Session 2026-07-12, user device Fosmon Mini BT Keyboard + Touchpad (Amazon B00BX0YKX4, short link https://a.co/d/0fg4vprm). Field fix for Tactility HID Host. ### Typical Reports - Keyboard: 8 bytes boot `[mod, 0x00, key0..key5]` optionally prefixed with Report ID 1 → 9 bytes `[0x01, mod, 0, k0..k5]` - Mouse/touchpad: 3-5 bytes `[buttons, x_rel, y_rel, wheel, pan]` optionally `[ID, ...]` - Fosmon: likely `[btn, x, y, wheel]` 4 bytes, Report ID 2 → notify `[0x02, btn, x, y]` or `[btn, x, y, wheel]` - Logitech high-res: 5 bytes packed 12-bit `[btn, ?, x_low, x_hi_nibble|y_low_nibble, y_high]` ### Old Code Failure ```cpp if (len >=5) { raw_x = data[2] | ((data[3] & 0x0F)<<8); // treats wheel as nibble ... } ``` For standard packet `[0x01 btn, 0x05 dx, 0xFE dy (-2), 0x00 wheel, 0x00]` → raw_x = 0xFE | (0x00<<8)=254 → sign-extend → large jump. ### Fixed Code Snippet ```cpp static void hidHostHandleMouseReportInternal(const uint8_t* data, uint16_t len, uint8_t expected_report_id) { const uint8_t *p=data; uint16_t plen=len; if (expected_report_id!=0 && len>=2 && data[0]==expected_report_id) { p=data+1; plen=len-1; } if (plen<3) return; if (plen>=5) { int8_t std_dx=(int8_t)p[1], std_dy=(int8_t)p[2]; int16_t raw_x12 = p[2] | ((p[3]&0x0F)<<8); if (raw_x12&0x0800) raw_x12|=0xF000; int16_t raw_y12 = (int16_t)((p[3]>>4)|(p[4]<<4)); if (raw_y12&0x0800) raw_y12|=0xF000; bool std_small = abs(std_dx)<=48 && abs(std_dy)<=48; bool s12_large = abs(raw_x12)>128 || abs(raw_y12)>128; // heuristic: small std + large 12 → std (touchpad) // large std pathological + plausible 12 <=300 → 12-bit (Logitech) } else { btn=p[0]&1; dx=(int8_t)p[1]; dy=(int8_t)p[2]; } } ``` ### Keyboard ID Strip Same pattern for keyboardInternal. ### NOTIFY_RX Dispatch Update Pass `rpt.reportId` to Internal variants. For Unknown type, compute effective_len stripping ID, then route by len >=8 keyboard else >=3 mouse. ### Files Changed - Tactility/Source/bluetooth/BluetoothHidHost.cpp: added Internal variants, heuristic, ID strip, retry timer `hid_autoconn_retry_timer`, dual addr_type try