Give model specific braille display gestures priority over generic gestures again (#20991)
Fixes #20961
Summary of the issue:
Since 2026.3beta1, the outer dual-action buttons on a EuroBraille B.note no longer scroll the braille display when pressed lightly. They move the review cursor by character instead.
The cause is a regression in BrailleDisplayGesture._get_identifiers from #20028 (multi routing). When a gesture has no cell indexes, the model specific identifier is inserted at index 1, after the generic identifier, instead of at index 0. Script lookup walks normalizedIdentifiers in order, so a generic binding for the same key now wins over the model specific one.
For the B.note, br(eurobraille.bnote):joystick1Right is bound to braille_scrollForward. However, br(eurobraille):joystick1Right (bound to review_nextCharacter) comes first, and that is what runs. Input help shows the same thing.
Other model specific bindings in NVDA are affected in the same way:
HIMS Smart Beetle and Braille EDGE f1–f4 bindings
Handy Tech Easy Braille left/right+b1+b3+b4
any model specific gestures assigned by users in the Input Gestures dialog or defined by add-on drivers
Gestures with cell indexes (for example routing) were not affected, because that branch already inserts the model specific identifiers first.
Description of user facing changes:
Model specific braille display gestures take priority over generic ones again, as they did in 2026.2. On a EuroBraille B.note, a light press of the outer buttons scrolls the braille display back and forward again.
Description of developer facing changes:
None. BrailleDisplayGesture.identifiers once again lists br(source.model):id before br(source):id when the gesture has no cell indexes.
Description of development approach:
The model specific identifier is now inserted at index 0 when there are no cell indexes. With cell indexes, the order is unchanged: model specific with indexes, model specific, generic with indexes, generic.