Skip to content

Accept keys in indeterminate order in KeyboardInputGesture.fromName - #20647

Closed
LeonarddeR wants to merge 2 commits into
nvaccess:masterfrom
LeonarddeR:i8201
Closed

Accept keys in indeterminate order in KeyboardInputGesture.fromName#20647
LeonarddeR wants to merge 2 commits into
nvaccess:masterfrom
LeonarddeR:i8201

Conversation

@LeonarddeR

Copy link
Copy Markdown
Collaborator

Link to issue number:

Fixes #8201

Summary of the issue:

NVDA can create a keyboard gesture from a written key name. It treats the last key in the name as the main key. All other keys become modifiers. Hand-written names do not always place the main key last. The name "alt+b+control" then yields a gesture with control as the main key and the letter b as a modifier. A letter has no modifier name. The gesture identifier therefore becomes the garbage value kb:+alt+control. The intended key is lost. Invalid key names also escape with an undocumented KeyError.

Description of user facing changes:

None. This change is developer oriented.

Description of developer facing changes:

KeyboardInputGesture.fromName now treats the non modifier key as the main key, regardless of its position in the name. Names containing only modifiers keep the last key as the main key. The method raises ValueError for a name with multiple non modifier keys, an unknown key name, or an empty name. Unknown names previously escaped with KeyError.

Description of development approach:

fromName resolves each key name in the sequence to a virtual key code. It used the last resolved key as the main key. This is only correct when the main key is written last.

The resolution of a single key name moves to a new _resolveKeyName classmethod. It returns virtual key code / extended flag pairs. For a character, it also returns the modifiers required to produce that character. Lookup failures propagate as LookupError.

fromName collects the resolved keys and re-raises lookup failures as ValueError. It then determines which keys are modifiers. A key is a modifier when its code is in NORMAL_MODIFIER_KEYS or when it is an NVDA modifier key. This is the same test the gesture itself uses for its isModifier property. More than one non modifier key raises ValueError. The single non modifier key becomes the main key. When there is none, the last key remains the main key. Names for bare modifiers therefore keep working.

Testing strategy:

New unit test module tests/unit/test_keyboardHandler.py. The tests cover:

  • The same gesture results with the main key in first, middle or last position.
  • Normalized identifiers are equal regardless of key order in the name.
  • Names with only modifiers and single modifier names keep their current meaning.
  • The NVDA modifier key is treated as a modifier.
  • ValueError is raised for multiple main keys, a duplicated main key, an unknown key name and an empty name.

The tests were written first and failed against the old implementation.

Known issues with pull request:

None known.

Code Review Checklist:

  • Documentation:
    • Change log entry
    • User Documentation
    • Developer / Technical Documentation
    • Context sensitive help for GUI changes
  • Testing:
    • Unit tests
    • System (end to end) tests
    • Manual testing
  • UX of all users considered:
    • Speech
    • Braille
    • Low Vision
    • Different web browsers
    • Localization in other languages / culture than English
  • API is compatible with existing add-ons.
  • Security precautions taken.

LeonarddeR and others added 2 commits August 11, 2026 09:35
… key

The main key is the non modifier key, regardless of its position in the name.
Names containing only modifiers keep the last key as the main key.
fromName raises ValueError for multiple non modifier keys, unknown key names and empty names.
Key name resolution moves to a new _resolveKeyName classmethod.
Add unit tests for fromName.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@LeonarddeR
LeonarddeR marked this pull request as ready for review August 11, 2026 10:42
@LeonarddeR
LeonarddeR requested a review from a team as a code owner August 11, 2026 10:42
@LeonarddeR
LeonarddeR requested review from SaschaCowley and a lite review from Copilot August 11, 2026 10:42

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR improves keyboardHandler.KeyboardInputGesture.fromName so written key names can be parsed correctly even when the “main” (non-modifier) key is not last, and so invalid inputs raise documented ValueErrors instead of leaking KeyError. This aligns gesture parsing behavior with how NVDA treats modifier vs main keys elsewhere, and prevents malformed identifiers when users/devs provide unordered key sequences.

Changes:

  • Refactors single-key resolution into KeyboardInputGesture._resolveKeyName, centralizing virtual-key lookup and modifier expansion for characters.
  • Updates KeyboardInputGesture.fromName to select the (single) non-modifier key as the main key regardless of position; keeps legacy behavior for names containing only modifiers; normalizes lookup failures to ValueError.
  • Adds unit tests covering key-order independence and new error cases, plus a changelog entry.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
source/keyboardHandler.py Refactors key-name resolution and updates fromName main-key selection + error handling to accept indeterminate key order.
tests/unit/test_keyboardHandler.py Adds unit tests for reordered key names, NVDA modifier handling, and ValueError cases.
user_docs/en/changes.md Documents the developer-facing behavior change and new ValueError semantics.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@seanbudd

Copy link
Copy Markdown
Member

Hi @LeonarddeR #8201 still hasn't been triaged yet. Closing until we have triaged and decided on an acceptable solution

@seanbudd seanbudd closed this Aug 13, 2026
@LeonarddeR

Copy link
Copy Markdown
Collaborator Author

@seanbudd please note that @SaschaCowley wrote:

Regardless, we do think that this logic should be tightened up.

I considered this as a go. Note that the fact that there is a bug in play here, although small, is really evident.
I'm happy to triage the issue myself if that takes some burden off your hands.

@seanbudd

Copy link
Copy Markdown
Member

Please read the triaging docs we don't allow contributors to triage their own issues

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Improve keyboardHandler.KeyboardInputGesture.fromName to accept keys in indeterminate order

3 participants