Skip to content

fix: add legacy SS3 modifier support#894

Merged
gdamore merged 1 commit intomainfrom
gdamore-old-ss3-modifiers
Dec 7, 2025
Merged

fix: add legacy SS3 modifier support#894
gdamore merged 1 commit intomainfrom
gdamore-old-ss3-modifiers

Conversation

@gdamore
Copy link
Owner

@gdamore gdamore commented Dec 7, 2025

Summary by CodeRabbit

  • Bug Fixes

    • Improved handling of special key sequences to correctly recognize and apply modifier keys (including legacy SS3-style modifiers), resulting in more accurate key events.
    • Preserved existing simple-key behavior while extending support for modifier-bearing sequences.
  • Tests

    • Added comprehensive tests covering special keys, CSI/SS3 sequences, function keys, and various modifier combinations.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 7, 2025

Walkthrough

SS3 escape-sequence handling was extended to accumulate CSI-like parameters, parse semicolon-delimited modifier values, and emit SS3 keys with calculated modifiers. Tests were expanded with a comprehensive TestSpecialKeys suite covering CSI/SS3 sequences and modifier combinations.

Changes

Cohort / File(s) Summary
SS3 Modifier Support
input.go
On entering SS3, clears CSI param buffer; while in SS3 accepts 0x30–0x3F bytes into ip.csiParams, parses semicolon-delimited parts, and emits SS3 keys with computed modifiers when params indicate modifiers. Retains simple-key behavior when no params.
Test Coverage: Special Keys
input_test.go
Adds TestSpecialKeys covering ESC, Tab, Enter variants, CSI and SS3 sequences, and modifier combinations. Minor test formatting tweaks and small control-key handling adjustments.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Focus review on: parameter accumulation in SS3 state, parsing of ip.csiParams (edge cases like empty parts), modifier calculation logic, and the new TestSpecialKeys expectations.

Poem

🐰 I hopped through bytes and counted each part,
Semicolons singing, modifiers start,
SS3 keys now wear a ribbon so fine,
Tests clap their paws in a neat little line,
Whispering: "Press onward, input — align!"

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: adding support for legacy SS3 modifier handling, which aligns with the core modifications in input.go.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch gdamore-old-ss3-modifiers

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

Copy link
Contributor

@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.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b407df3 and 57c7416.

📒 Files selected for processing (2)
  • input.go (2 hunks)
  • input_test.go (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
input.go (1)
key.go (2)
  • NewEventKey (249-308)
  • ModNone (325-325)
input_test.go (2)
key.go (30)
  • KeyEscape (517-517)
  • ModNone (325-325)
  • KeyRune (339-339)
  • ModCtrl (321-321)
  • KeyCtrlA (443-443)
  • Key (332-332)
  • ModMask (312-312)
  • KeyTab (515-515)
  • KeyEnter (518-518)
  • KeyBackspace (514-514)
  • KeyEnd (352-352)
  • KeyHome (351-351)
  • KeyInsert (353-353)
  • KeyF1 (362-362)
  • KeyF2 (363-363)
  • KeyF4 (365-365)
  • KeyBacktab (361-361)
  • ModShift (320-320)
  • KeyF5 (366-366)
  • KeyF6 (367-367)
  • KeyF7 (368-368)
  • KeyF8 (369-369)
  • KeyF9 (370-370)
  • KeyF10 (371-371)
  • KeyF11 (372-372)
  • KeyF12 (373-373)
  • KeyF3 (364-364)
  • ModMeta (323-323)
  • NewEventKey (249-308)
  • EventKey (45-50)
event.go (1)
  • Event (23-26)
🔇 Additional comments (5)
input_test.go (3)

89-93: LGTM!

Comment formatting improvements enhance readability.


276-279: LGTM!

Comment formatting improvements.


552-561: Good test coverage for SS3 modifier formats.

The tests cover the key SS3 modifier formats: standard 1;mod, short form mod, and empty-prefix ;mod. This aligns well with the implementation in input.go.

input.go (2)

449-452: LGTM!

Resetting csiParams when entering SS3 state ensures clean parameter accumulation for SS3 sequences with modifiers.


506-527: Verify handling of unexpected SS3 parameter formats.

The modifier parsing logic at lines 519-525 handles specific formats (1;mod, ;mod, mod), but if a sequence has an unexpected first parameter (e.g., ESC O 2;5 P), no event is posted. This may be intentional to ignore non-conforming sequences, but could also silently drop valid user input from uncommon terminals.

Consider whether a fallback to emit the key with ModNone would be safer:

 			} else if parts := strings.Split(string(ip.csiParams), ";"); len(parts) >= 1 {
 				// SS3 with modifier (old style).  Note old terminfo would declare these as high
 				// numbered function keys, but we encode as modified since that's how they are entered.
 				if len(parts) >= 2 {
 					if m, err := strconv.Atoi(parts[1]); err == nil && (parts[0] == "1" || parts[0] == "") {
 						ip.post(NewEventKey(k, "", calcModifier(m)))
+					} else {
+						// Unrecognized format, emit key without modifiers
+						ip.post(NewEventKey(k, "", ModNone))
 					}
 				} else if m, err := strconv.Atoi(parts[0]); err == nil {
 					ip.post(NewEventKey(k, "", calcModifier(m)))
+				} else {
+					// Failed to parse modifier, emit key without modifiers
+					ip.post(NewEventKey(k, "", ModNone))
 				}
 			}

If the current behavior is intentional (ignoring non-conforming sequences), a brief comment would help clarify this design choice.

While here update for loops to modern go range loops.
@gdamore gdamore force-pushed the gdamore-old-ss3-modifiers branch from 57c7416 to 27832af Compare December 7, 2025 19:15
Copy link
Contributor

@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.

Actionable comments posted: 0

🧹 Nitpick comments (1)
input_test.go (1)

515-587: Comprehensive CSI/SS3 special-key coverage; only minor nits

The new TestSpecialKeys table is a solid, centralized way to validate CSI and SS3 sequences and modifier handling, including the legacy SS3 modifier forms and mixed encodings.

Two small, optional nits:

  • The error message "Timeout waiting for UTF-8 character event" is a bit misleading here since many cases are non-UTF8 control sequences; consider a more generic message like "special key event" if you touch this again.
  • If you ever need stricter regression checks, you might also assert Str() for a few representative entries (e.g., ESC vs Tab/Enter) to catch accidental string changes.

These are polish-only; the functional expectations (keys + modifiers) look consistent with the described behavior.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 57c7416 and 27832af.

📒 Files selected for processing (2)
  • input.go (2 hunks)
  • input_test.go (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • input.go
🧰 Additional context used
🧬 Code graph analysis (1)
input_test.go (2)
key.go (9)
  • ModNone (325-325)
  • KeyRune (339-339)
  • ModCtrl (321-321)
  • KeyCtrlA (443-443)
  • Key (332-332)
  • ModMask (312-312)
  • ModShift (320-320)
  • NewEventKey (249-308)
  • EventKey (45-50)
event.go (1)
  • Event (23-26)
🔇 Additional comments (3)
input_test.go (3)

89-93: Control-key coverage for 0x1B–0x1F looks correct

The added cases for ESC and 0x1C–0x1F (mapping to KeyEscape and KeyRune with ModCtrl) align with the documented NewEventKey behavior and nicely complete the control-key table.


276-279: Sequential input expectations match null-byte semantics

The updated expectations for the sequential inputs—especially treating 0x00 as KeyRune + " " + ModCtrl—are consistent with the earlier null-byte tests and ensure queue ordering is exercised.


443-459: for range 10 is valid Go syntax as of Go 1.22 and is perfectly acceptable in this codebase (which requires Go 1.24.0 per go.mod). No changes are needed.

Likely an incorrect or invalid review comment.

@gdamore gdamore merged commit 866fd71 into main Dec 7, 2025
13 checks passed
@gdamore gdamore deleted the gdamore-old-ss3-modifiers branch December 7, 2025 19:56
@coderabbitai coderabbitai bot mentioned this pull request Jan 26, 2026
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.

1 participant