Coverage for src / bluetooth_sig / gatt / characteristics / boot_keyboard_input_report.py: 100%

37 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-03-18 11:17 +0000

1"""Boot Keyboard Input Report characteristic implementation.""" 

2 

3from __future__ import annotations 

4 

5from enum import IntFlag 

6 

7import msgspec 

8 

9from ...types.gatt_enums import CharacteristicRole 

10from ..constants import SIZE_UINT16 

11from ..context import CharacteristicContext 

12from .base import BaseCharacteristic 

13 

14 

15class KeyboardModifiers(IntFlag): 

16 """Keyboard modifier keys bitmap.""" 

17 

18 LEFT_CTRL = 0x01 

19 LEFT_SHIFT = 0x02 

20 LEFT_ALT = 0x04 

21 LEFT_GUI = 0x08 

22 RIGHT_CTRL = 0x10 

23 RIGHT_SHIFT = 0x20 

24 RIGHT_ALT = 0x40 

25 RIGHT_GUI = 0x80 

26 

27 

28class BootKeyboardInputReportData(msgspec.Struct, frozen=True, kw_only=True): 

29 """Boot keyboard input report data. 

30 

31 Attributes: 

32 modifiers: Modifier keys state bitmap 

33 reserved: Reserved byte (always 0) 

34 keycodes: Up to 6 simultaneous key codes (HID usage IDs) 

35 """ 

36 

37 modifiers: KeyboardModifiers 

38 reserved: int 

39 keycodes: tuple[int, ...] 

40 

41 

42class BootKeyboardInputReportCharacteristic(BaseCharacteristic[BootKeyboardInputReportData]): 

43 """Boot Keyboard Input Report characteristic (0x2A22). 

44 

45 org.bluetooth.characteristic.boot_keyboard_input_report 

46 

47 Contains keyboard input report data in boot mode following USB HID boot protocol. 

48 Format: 1-8 bytes - modifier(1) + [reserved(1) + keycodes(0-6)]. 

49 

50 Spec Reference: 

51 USB HID Specification v1.11, Appendix B - Boot Interface Descriptors 

52 """ 

53 

54 _manual_role = CharacteristicRole.INFO 

55 min_length = 1 

56 max_length = 8 

57 allow_variable_length = True 

58 

59 def _decode_value( 

60 self, data: bytearray, ctx: CharacteristicContext | None = None, *, validate: bool = True 

61 ) -> BootKeyboardInputReportData: 

62 """Parse HID keyboard report. 

63 

64 Args: 

65 data: Raw bytearray from BLE characteristic (1-8 bytes). 

66 ctx: Optional CharacteristicContext. 

67 validate: Whether to validate ranges (default True) 

68 

69 Returns: 

70 BootKeyboardInputReportData with parsed keyboard state. 

71 """ 

72 modifiers = KeyboardModifiers(data[0]) 

73 reserved = data[1] if len(data) >= SIZE_UINT16 else 0 

74 keycodes = tuple(data[i] for i in range(2, len(data))) 

75 

76 return BootKeyboardInputReportData( 

77 modifiers=modifiers, 

78 reserved=reserved, 

79 keycodes=keycodes, 

80 ) 

81 

82 def _encode_value(self, data: BootKeyboardInputReportData) -> bytearray: 

83 """Encode keyboard report to bytes. 

84 

85 Args: 

86 data: BootKeyboardInputReportData to encode 

87 

88 validate: Whether to validate ranges (default True) 

89 

90 Returns: 

91 Encoded bytes (8 bytes total) 

92 """ 

93 result = bytearray(8) 

94 result[0] = int(data.modifiers) 

95 result[1] = data.reserved 

96 

97 # Encode up to 6 keycodes 

98 for i, keycode in enumerate(data.keycodes[:6]): 

99 result[2 + i] = keycode 

100 

101 return result