Skip to content

Keyboard controls for Select gizmo#543

Merged
tracygardner merged 3 commits intoflipcomputing:mainfrom
lawsie:select-keyboard-controls
Apr 16, 2026
Merged

Keyboard controls for Select gizmo#543
tracygardner merged 3 commits intoflipcomputing:mainfrom
lawsie:select-keyboard-controls

Conversation

@lawsie
Copy link
Copy Markdown
Contributor

@lawsie lawsie commented Apr 16, 2026

Summary

  • The select (arrow) gizmo can now be controlled by the arrow keys to move, and Enter to choose
  • The cursor displays as a 🚫 if the cursor is not hovering on something selectable

Things this does NOT do

  • The canvas cursor does NOT automatically appear if keyboard controls are being used, pending a decision on Show canvas cursor immediately if KB controls used to select gizmo #542 - I'll alter this everywhere in a separate PR if it's decided that is what we want.
  • The corresponding block is displayed correctly in the editor when you select a mesh. HOWEVER the keyboard focus is not transferred to that block. This is because it isn't a simple thing to do without getting into a fight with Blockly.

Claude Sonnet 4.6 wrote the applySelection function within gizmos.js but this reuses most of the existing code. It's mainly there so that both mouse and keyboard controls can use the same code.

Part of #360

Summary by CodeRabbit

  • New Features

    • Added position readouts when selecting gizmos or picking points on the canvas.
  • Improvements

    • Enhanced selection and deselection handling for improved consistency.
    • Better differentiation between ground picks and mesh selections with appropriate responses.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 16, 2026

Warning

Rate limit exceeded

@lawsie has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 31 minutes and 36 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 31 minutes and 36 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3acf6b5d-9c7f-4d5a-8f0a-62d914a05242

📥 Commits

Reviewing files that changed from the base of the PR and between 73f61f3 and 82d7d4a.

📒 Files selected for processing (1)
  • ui/gizmos.js
📝 Walkthrough

Walkthrough

Refactored handleSelectGizmo() by introducing an applySelection() helper to centralize selection/deselection behavior. Control flow changed from immediate event.pickInfo processing to deferred click handling via setTimeout with startCanvasKeyboardMode, performing scene.pick() before applying selection. Position readouts and gizmo attachment logic updated accordingly.

Changes

Cohort / File(s) Summary
Selection Handling Refactor
ui/gizmos.js
Extracted shared selection/deselection logic into applySelection() helper. Modified control flow to defer selection processing via setTimeout and startCanvasKeyboardMode. Updated position readouts, gizmo attachment behavior, and pointer observer to delegate to applySelection() before cleanup.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰 A gizmo's dance, now refactored with care,
Selection helpers hop through canvas air,
With timeouts and keyboard modes so bright,
The pointer picks meshes—a joyful sight! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Keyboard controls for Select gizmo' accurately reflects the main change: adding keyboard functionality to the select gizmo, which is well-supported by the PR objectives and code refactoring.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
ui/gizmos.js (1)

903-943: ⚠️ Potential issue | 🔴 Critical

Bug: blockKey references the previously selected mesh, not the newly picked one.

The applySelection function uses the outer-scoped blockKey (line 922) to look up and highlight the associated block. However, blockKey is set from gizmoManager.attachedMesh (the old selection) in both callers before applySelection is invoked. This causes the wrong block to be highlighted when selecting a new mesh.

The highlighted block will be from the previous selection, while the gizmo attaches to the new mesh.

🐛 Proposed fix: derive blockKey from the picked mesh
 function applySelection(pickedMesh, pickedPoint) {
   if (pickedMesh && pickedMesh.name !== "ground") {
     const position = pickedMesh.getAbsolutePosition();
     const roundedPosition = roundVectorToFixed(position, 2);
     flock.printText({
       text: translate("position_readout").replace(
         "{position}",
         String(roundedPosition),
       ),
       duration: 30,
       color: "black",
     });
     if (flock.meshDebug) console.log(pickedMesh.parent);
     if (pickedMesh.parent) {
       pickedMesh = getRootMesh(pickedMesh.parent);
       if (flock.meshDebug) console.log(pickedMesh.visibility);
       pickedMesh.visibility = 0.001;
       if (flock.meshDebug) console.log(pickedMesh.visibility);
     }
-    const block = meshMap[blockKey];
+    const newBlockKey = findParentWithBlockId(pickedMesh)?.metadata?.blockKey;
+    const block = meshMap[newBlockKey];
     highlightBlockById(Blockly.getMainWorkspace(), block);
     gizmoManager.attachToMesh(pickedMesh);
     pickedMesh.showBoundingBox = true;
   } else {

With this fix, the outer blockKey variable and its assignments in the callers (lines 952-953, 974-975) become unnecessary and can be removed for cleanup.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ui/gizmos.js` around lines 903 - 943, applySelection is using an outer-scoped
blockKey (based on the previous selection) instead of deriving the block key
from the newly picked mesh; change applySelection to compute blockKey from the
picked mesh (use getRootMesh(pickedMesh or pickedMesh.parent) as needed), look
up the block with meshMap[derivedBlockKey], and pass that block into
highlightBlockById(Blockly.getMainWorkspace(), block) before attaching the
gizmo; also remove the now-unnecessary outer-scope blockKey assignments that
were set from gizmoManager.attachedMesh in the callers so selection highlighting
is always derived from the current picked mesh.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@ui/gizmos.js`:
- Around line 903-943: applySelection is using an outer-scoped blockKey (based
on the previous selection) instead of deriving the block key from the newly
picked mesh; change applySelection to compute blockKey from the picked mesh (use
getRootMesh(pickedMesh or pickedMesh.parent) as needed), look up the block with
meshMap[derivedBlockKey], and pass that block into
highlightBlockById(Blockly.getMainWorkspace(), block) before attaching the
gizmo; also remove the now-unnecessary outer-scope blockKey assignments that
were set from gizmoManager.attachedMesh in the callers so selection highlighting
is always derived from the current picked mesh.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b70b1765-df59-4403-816a-ab5951b3c50b

📥 Commits

Reviewing files that changed from the base of the PR and between 03ab56f and 73f61f3.

📒 Files selected for processing (1)
  • ui/gizmos.js

@lawsie lawsie marked this pull request as draft April 16, 2026 10:43
@lawsie lawsie marked this pull request as ready for review April 16, 2026 11:02
@lawsie lawsie mentioned this pull request Apr 16, 2026
11 tasks
@tracygardner tracygardner merged commit 93310e8 into flipcomputing:main Apr 16, 2026
5 checks passed
@lawsie lawsie deleted the select-keyboard-controls branch April 20, 2026 08:23
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.

2 participants