44# Copyright (C) 2021 NV Access Limited
55
66from dataclasses import dataclass
7- from typing import List , Optional
7+ from typing import List
88import enum
9+ import itertools
910import braille
1011import inputCore
1112from logHandler import log
@@ -90,7 +91,8 @@ def registerAutomaticDetection(cls, driverRegistrar: DriverRegistrar):
9091
9192 def __init__ (self , port = "auto" ):
9293 super ().__init__ ()
93- self .numCells = 0
94+ self .numRows = 1
95+ self .numCols = 0
9496
9597 for portType , portId , port , portInfo in self ._getTryPorts (port ):
9698 if portType != bdDetect .DeviceType .HID :
@@ -103,16 +105,27 @@ def __init__(self, port="auto"):
103105 continue # Couldn't connect.
104106 if self ._dev .usagePage != HID_USAGE_PAGE_BRAILLE :
105107 log .debug ("Not braille" )
108+ self ._dev .close ()
106109 continue
107110 cellValueCaps = self ._findCellValueCaps ()
108- if cellValueCaps :
111+ if len (cellValueCaps ) > 0 :
112+ if any (x .ReportCount != cellValueCaps [0 ].ReportCount for x in cellValueCaps ):
113+ log .warning ("Found multi-line display with an irregular shape, ignoring." )
114+ self ._dev .close ()
115+ continue
116+ self .numRows = len (cellValueCaps )
117+ self .numCols = cellValueCaps [0 ].ReportCount
118+ self ._maxNumberOfCells = self .numCells
109119 self ._cellValueCaps = cellValueCaps
110- self ._numberOfCellsValueCaps = self ._findNumberOfCellsValueCaps ()
111- self .numCells = self ._maxNumberOfCells = cellValueCaps .ReportCount
120+ if self .numRows == 1 :
121+ self ._numberOfCellsValueCaps = self ._findNumberOfCellsValueCaps ()
122+ elif self ._findNumberOfCellsValueCaps ():
123+ log .warning ("Reserved braille cells are not supported on multi-line displays" )
112124 # A display responded.
113125 log .info (
114- "Found display with {cells} cells connected via {type} ({port})" .format (
115- cells = self .numCells ,
126+ "Found display with {rows} rows, {cols} cols connected via {type} ({port})" .format (
127+ rows = self .numRows ,
128+ cols = self .numCols ,
116129 type = portType ,
117130 port = port ,
118131 ),
@@ -126,8 +139,10 @@ def __init__(self, port="auto"):
126139 self ._keysDown = set ()
127140 self ._ignoreKeyReleases = False
128141
129- def _findCellValueCaps (self ) -> Optional [hidpi .HIDP_VALUE_CAPS ]:
130- for valueCaps in self ._dev .outputValueCaps :
142+ def _findCellValueCaps (self ) -> list [hidpi .HIDP_VALUE_CAPS ]:
143+ return [
144+ valueCaps
145+ for valueCaps in self ._dev .outputValueCaps
131146 if (
132147 valueCaps .LinkUsagePage == HID_USAGE_PAGE_BRAILLE
133148 and valueCaps .LinkUsage == BraillePageUsageID .BRAILLE_ROW
@@ -137,9 +152,8 @@ def _findCellValueCaps(self) -> Optional[hidpi.HIDP_VALUE_CAPS]:
137152 BraillePageUsageID .SIX_DOT_BRAILLE_CELL ,
138153 )
139154 and valueCaps .ReportCount > 0
140- ):
141- return valueCaps
142- return None
155+ )
156+ ]
143157
144158 def _findNumberOfCellsValueCaps (self ) -> hidpi .HIDP_VALUE_CAPS | None :
145159 for valueCaps in self ._dev .inputValueCaps :
@@ -226,14 +240,22 @@ def display(self, cells: List[int]):
226240 # cells will already be padded up to numCells.
227241 padded_cells = cells + [0 ] * (self ._maxNumberOfCells - len (cells ))
228242 cellBytes = b"" .join (intToByte (cell ) for cell in padded_cells )
229- report = hwIo .hid .HidOutputReport (self ._dev , reportID = self ._cellValueCaps .ReportID )
230- report .setUsageValueArray (
231- HID_USAGE_PAGE_BRAILLE ,
232- self ._cellValueCaps .LinkCollection ,
233- self ._cellValueCaps .u1 .NotRange .Usage ,
234- cellBytes ,
235- )
236- self ._dev .write (report .data )
243+ # Iterate through the output reports
244+ for reportID , valueCaps in itertools .groupby (self ._cellValueCaps , lambda x : x .ReportID ):
245+ report = hwIo .hid .HidOutputReport (self ._dev , reportID = reportID )
246+ # Iterate through each row in this report
247+ for valueCap in valueCaps :
248+ # Take the cells for this row from the front of the cellBytes list
249+ rowCellBytes = cellBytes [: valueCap .ReportCount ]
250+ cellBytes = cellBytes [valueCap .ReportCount :]
251+
252+ report .setUsageValueArray (
253+ HID_USAGE_PAGE_BRAILLE ,
254+ valueCap .LinkCollection ,
255+ valueCap .u1 .NotRange .Usage ,
256+ rowCellBytes ,
257+ )
258+ self ._dev .write (report .data )
237259
238260 gestureMap = inputCore .GlobalGestureMap (
239261 {
0 commit comments