Coverage for src / bluetooth_sig / gatt / characteristics / boot_mouse_input_report.py: 97%
36 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-03-18 11:17 +0000
« prev ^ index » next coverage.py v7.13.5, created at 2026-03-18 11:17 +0000
1"""Boot Mouse Input Report characteristic implementation."""
3from __future__ import annotations
5from enum import IntFlag
7import msgspec
9from ...types.gatt_enums import CharacteristicRole
10from ..constants import SIZE_UINT32
11from ..context import CharacteristicContext
12from .base import BaseCharacteristic
13from .utils import DataParser
16class MouseButtons(IntFlag):
17 """Mouse button states bitmap."""
19 LEFT = 0x01
20 RIGHT = 0x02
21 MIDDLE = 0x04
24class BootMouseInputReportData(msgspec.Struct, frozen=True, kw_only=True):
25 """Boot mouse input report data.
27 Attributes:
28 buttons: Mouse button states bitmap
29 x_displacement: Horizontal movement (signed, -127 to 127)
30 y_displacement: Vertical movement (signed, -127 to 127)
31 wheel: Optional scroll wheel movement (signed, -127 to 127)
32 """
34 buttons: MouseButtons
35 x_displacement: int
36 y_displacement: int
37 wheel: int | None = None
40class BootMouseInputReportCharacteristic(BaseCharacteristic[BootMouseInputReportData]):
41 """Boot Mouse Input Report characteristic (0x2A33).
43 org.bluetooth.characteristic.boot_mouse_input_report
45 Contains mouse input report data in boot mode following USB HID boot protocol.
46 Format: 3-4 bytes - buttons(1) + X(1) + Y(1) + [wheel(1)].
48 Spec Reference:
49 USB HID Specification v1.11, Appendix B - Boot Interface Descriptors
50 """
52 _manual_role = CharacteristicRole.INFO
53 min_length = 3
54 max_length = 4
55 allow_variable_length = True
57 def _decode_value(
58 self, data: bytearray, ctx: CharacteristicContext | None = None, *, validate: bool = True
59 ) -> BootMouseInputReportData:
60 """Parse HID mouse report.
62 Args:
63 data: Raw bytearray from BLE characteristic (3-4 bytes).
64 ctx: Optional CharacteristicContext.
65 validate: Whether to validate ranges (default True)
67 Returns:
68 BootMouseInputReportData with parsed mouse state.
69 """
70 buttons = MouseButtons(data[0])
71 x_displacement = DataParser.parse_int8(data, 1, signed=True)
72 y_displacement = DataParser.parse_int8(data, 2, signed=True)
73 wheel = DataParser.parse_int8(data, 3, signed=True) if len(data) == SIZE_UINT32 else None
75 return BootMouseInputReportData(
76 buttons=buttons,
77 x_displacement=x_displacement,
78 y_displacement=y_displacement,
79 wheel=wheel,
80 )
82 def _encode_value(self, data: BootMouseInputReportData) -> bytearray:
83 """Encode mouse report to bytes.
85 Args:
86 data: BootMouseInputReportData to encode
88 validate: Whether to validate ranges (default True)
90 Returns:
91 Encoded bytes (3-4 bytes depending on wheel presence)
92 """
93 result = bytearray()
94 result.append(int(data.buttons))
95 result.extend(DataParser.encode_int8(data.x_displacement, signed=True))
96 result.extend(DataParser.encode_int8(data.y_displacement, signed=True))
98 if data.wheel is not None:
99 result.extend(DataParser.encode_int8(data.wheel, signed=True))
101 return result