Skip to content

feat: add key modifiers to layout configuration#202

Merged
conventoangelo merged 7 commits into
mainfrom
feat/key-modifiers
Jul 19, 2026
Merged

feat: add key modifiers to layout configuration#202
conventoangelo merged 7 commits into
mainfrom
feat/key-modifiers

Conversation

@conventoangelo

@conventoangelo conventoangelo commented Jul 19, 2026

Copy link
Copy Markdown
Owner

This pull request introduces support for key modifiers in custom layouts, allowing keys to have a separate top label, a tracked key, and a visual held state. It also adds new text settings for long labels and top labels, updates the configuration and serialization logic, and provides comprehensive documentation for these features. The most important changes are grouped below.


Key Modifier Support in Custom Layouts:

  • Added a KeyboardKeySpec class to represent keys with a tracked key, optional top label, and held/active visual state (type: "held"). This enables richer custom layouts and modifier keys.
  • Updated UserConfig parsing to support both plain string keys and object-based keys with modifier fields (h, t, type). Serialization logic now preserves these objects. [1] [2]
  • Modified the keyboard rendering logic to use the tracked key for press detection and shift mapping, and to visually indicate held-state keys.

Text Settings Enhancements:

  • Introduced new settings for long key font size and top label font size in KeyboardState, with corresponding update methods and serialization support. [1] [2] [3] [4] [5] [6] [7]
  • Updated the keyboard UI to use these sizes for long/alternate labels and top labels. [1] [2]

Documentation Updates:

  • Added docs/advanced/key-modifiers.md and docs/user-guide/text.md to explain key modifier objects and text settings. [1] [2]
  • Updated README.md and docs/index.md to reference the new key modifier and text settings documentation. [1] [2] [3] [4]
  • Updated preferences guide to mention long key and top label font size settings.

These changes make custom layouts much more flexible and improve the appearance and usability of complex keyboard overlays.

Summary by CodeRabbit

  • New Features

    • Added per-key “key modifiers” for custom layouts, including tracked keys, top labels, and held-key rendering.
    • Added new Text preferences to control long-key and top-label font sizes.
    • Enhanced key rendering to display metadata-driven top labels and use the new typography sizing.
  • Documentation

    • Added/updated guides for Text Settings and Key Modifiers, including configuration examples.
  • Tests

    • Extended tests for key modifier parsing/serialization and the new font-size preferences.

Copilot AI review requested due to automatic review settings July 19, 2026 04:42

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@coderabbitai

coderabbitai Bot commented Jul 19, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@conventoangelo, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 41 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 08e91223-00eb-481c-886a-b10dcc6f3382

📥 Commits

Reviewing files that changed from the base of the PR and between 41e4953 and 455944e.

📒 Files selected for processing (1)
  • lib/models/user_config.dart
📝 Walkthrough

Walkthrough

Adds typed key metadata for custom layouts, including tracked keys, top labels, and held states. Adds configurable long-key and top-label font sizes across state, preferences, rendering, serialization, tests, and documentation.

Changes

Key Modifiers and Text Settings

Layer / File(s) Summary
Key metadata model and configuration
lib/models/keyboard_layouts.dart, lib/models/user_config.dart, test/user_config_test.dart
Adds KeyboardKeySpec, parallel layout metadata, typed key JSON parsing/serialization, and coverage for metadata and held-state behavior.
Tracked-key and label rendering
lib/screens/keyboard_screen.dart, lib/widgets/options/base_option.dart
Uses tracked keys for pressed-state lookup and renders top labels and alternative layout keys with metadata-aware sizing. Test environments disable option splash effects.
Text sizing state and controls
lib/providers/keyboard_provider.dart, lib/services/method_call_handler.dart, lib/widgets/tabs/text_tab.dart, test/providers/keyboard_provider_test.dart
Adds long-key and top-label font-size state, persistence, method-call updates, preference sliders, synchronization, and tests.
User and advanced documentation
README.md, docs/index.md, docs/advanced/key-modifiers.md, docs/user-guide/preferences.md, docs/user-guide/text.md
Documents Key Modifiers and Text Settings and updates related navigation and formatting.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant TextTab
  participant KeyboardNotifier
  participant KeyboardState
  participant KeyboardScreen
  User->>TextTab: adjust font-size slider
  TextTab->>KeyboardNotifier: update font size
  KeyboardNotifier->>KeyboardState: copyWith updated sizing
  KeyboardScreen->>KeyboardState: read sizing and key metadata
  KeyboardScreen-->>User: render labels and keys
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: adding key modifier support to layout configuration.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/key-modifiers

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
lib/screens/keyboard_screen.dart (1)

212-217: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Cache altLayoutKey and reuse keyFontSize for clarity and efficiency.

You can simplify the widget tree and avoid invoking _getAltLayoutKey multiple times by computing the altLayoutKey upfront alongside keyFontSize. You can also reuse the pre-calculated keyFontSize variable for the primary key's Text widget instead of duplicating the ternary check.

♻️ Proposed refactor
     final topLabel = keySpec?.topLabel;
     final topLabelFontSize = keyboardState.topLabelFontSize;
+    final altLayoutKey = altLayout != null
+        ? _getAltLayoutKey(rowIndex, keyIndex, keyboardState, prefsState, altLayout)
+        : null;

Update the corresponding sections inside the Stack:

-                      if (altLayout != null)
+                      if (altLayoutKey != null)
                         Positioned(
                           top: 4,
                           left: 8,
                           child: Text(
                             key,
                             textAlign: TextAlign.left,
                             style: TextStyle(
                               color: textColor,
-                              fontSize: key.length > 2
-                                  ? keyboardState.longKeyFontSize
-                                  : keyboardState.keyFontSize,
+                              fontSize: keyFontSize,
                               fontWeight: keyboardState.fontWeight,
                             ),
                           ),
                         )

And for the alternative layout key:

-                      if (altLayout != null)
+                      if (altLayoutKey != null)
                         Positioned(
                           bottom: 4,
                           right: 8,
                           child: Text(
-                            _getAltLayoutKey(rowIndex, keyIndex, keyboardState,
-                                prefsState, altLayout),
+                            altLayoutKey,
                             textAlign: TextAlign.right,
                             style: TextStyle(
                               color: textColor,
-                              fontSize: _getAltLayoutKey(
-                                              rowIndex,
-                                              keyIndex,
-                                              keyboardState,
-                                              prefsState,
-                                              altLayout)
-                                          .length >
-                                      2
+                              fontSize: altLayoutKey.length > 2
                                   ? keyboardState.longKeyFontSize
                                   : keyboardState.keyFontSize,
                               fontWeight: keyboardState.fontWeight,
                             ),
                           ),
                         ),

Also applies to: 265-279, 310-333

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/screens/keyboard_screen.dart` around lines 212 - 217, Within the keyboard
widget-building method, cache the result of _getAltLayoutKey alongside
hasTopLabel and keyFontSize, then reuse altLayoutKey wherever the alternative
layout key is referenced instead of invoking the helper repeatedly. Update the
primary key Text widget to use the existing keyFontSize variable, and apply the
same reuse in the corresponding sections around the Stack and alternative-layout
handling.
lib/widgets/options/base_option.dart (1)

24-32: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Guard Platform.environment checks for web compatibility.

While this application might primarily target desktop platforms, importing dart:io and directly accessing Platform properties will cause UnsupportedError exceptions or compilation failures if the UI is ever run in a web environment.

As a best practice, consider guarding this with kIsWeb from flutter/foundation.dart.

🛠️ Proposed adjustment

Add the import at the top of the file:

+import 'package:flutter/foundation.dart';
 import 'dart:io';

And update the condition:

     // Disable splash effects during widget tests to avoid engine shader
     // runtime issues (ink_sparkle.frag mismatches). Only override in test
     // environment so production behavior isn't changed.
-    if (Platform.environment.containsKey('FLUTTER_TEST')) {
+    if (!kIsWeb && Platform.environment.containsKey('FLUTTER_TEST')) {
       return Theme(
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/widgets/options/base_option.dart` around lines 24 - 32, Guard the
FLUTTER_TEST environment check in the widget’s build logic using Flutter’s
kIsWeb indicator, ensuring Platform.environment is never accessed on web. Add
the foundation import and preserve the existing NoSplash Theme override for
non-web test environments and normal container behavior otherwise.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@lib/models/user_config.dart`:
- Around line 52-53: Update the trackedKey assignment in the key-mapping logic
to use an empty string when both the raw `t` value and topLabel are unavailable,
instead of falling back to rawKey.toString(). Preserve the existing precedence
for valid t values and topLabel.

In `@README.md`:
- Line 155: Update the documentation links in the README entries around “Key
modifiers” and “Text Settings” to use repository-relative paths such as docs/...
or ./docs/... instead of site-root-relative /docs/... paths. Normalize the moved
entries consistently while preserving their existing targets and labels.

---

Nitpick comments:
In `@lib/screens/keyboard_screen.dart`:
- Around line 212-217: Within the keyboard widget-building method, cache the
result of _getAltLayoutKey alongside hasTopLabel and keyFontSize, then reuse
altLayoutKey wherever the alternative layout key is referenced instead of
invoking the helper repeatedly. Update the primary key Text widget to use the
existing keyFontSize variable, and apply the same reuse in the corresponding
sections around the Stack and alternative-layout handling.

In `@lib/widgets/options/base_option.dart`:
- Around line 24-32: Guard the FLUTTER_TEST environment check in the widget’s
build logic using Flutter’s kIsWeb indicator, ensuring Platform.environment is
never accessed on web. Add the foundation import and preserve the existing
NoSplash Theme override for non-web test environments and normal container
behavior otherwise.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: cc0b7683-a774-4db7-96e1-80b31e16128f

📥 Commits

Reviewing files that changed from the base of the PR and between 02d12df and 783db91.

⛔ Files ignored due to path filters (3)
  • docs/advanced/image-1.png is excluded by !**/*.png
  • docs/advanced/image.png is excluded by !**/*.png
  • pubspec.lock is excluded by !**/*.lock
📒 Files selected for processing (14)
  • README.md
  • docs/advanced/key-modifiers.md
  • docs/index.md
  • docs/user-guide/preferences.md
  • docs/user-guide/text.md
  • lib/models/keyboard_layouts.dart
  • lib/models/user_config.dart
  • lib/providers/keyboard_provider.dart
  • lib/screens/keyboard_screen.dart
  • lib/services/method_call_handler.dart
  • lib/widgets/options/base_option.dart
  • lib/widgets/tabs/text_tab.dart
  • test/providers/keyboard_provider_test.dart
  • test/user_config_test.dart

Comment thread lib/models/user_config.dart Outdated
Comment thread README.md
conventoangelo and others added 2 commits July 19, 2026 12:54
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@conventoangelo
conventoangelo merged commit 6d9d1f2 into main Jul 19, 2026
5 checks passed
@conventoangelo
conventoangelo deleted the feat/key-modifiers branch July 19, 2026 05:06
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