Windows日本語IME対応#2
Conversation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Windows実機テスト結果全くキーボード操作を受け付けない。 日本語どころか英語も矢印キーも何も効かない。 以前の状態との差分前回(windows-v1.0.0)は英語入力は動いていた。今回動かなくなった原因候補: 1. focusNode変更(疑い度: 高)
// _TerminalTab
final FocusNode focusNode = FocusNode();
// _buildTerminalPane
TerminalView(
tab.terminal,
focusNode: tab.focusNode, // ← これが新しい
...
)TerminalView内部でもFocusNodeを作ってるので、外部から渡すと二重管理になってフォーカスが当たらない可能性がある。 2. autocompleteのonOutputラッパー(疑い度: 低)tab.terminal.onOutput = (data) {
tab.session?.write(...);
_onTerminalOutput(tab, data); // ← 追加
};デバッグ手順git stash # 一旦退避
# Step 1: focusNodeを外部から渡すのをやめてみる
# terminal_screen.dart の _buildTerminalPane で focusNode: tab.focusNode を削除
# → これで英語入力が復活するか確認
# Step 2: 復活したらfocusNodeが原因確定
# キーボードトグルボタンは別の方法で実装する |
Use GlobalKey instead of FocusNode for terminal reference. External FocusNode likely broke keyboard input on Windows. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
📝 WalkthroughWalkthroughデスクトップ向けにSplitViewを廃止して新たにDockView/DockViewControllerを導入、タブ描画とドラッグ/ドロップでの分割・移動を可能に。ターミナル画面はFocusNode→GlobalKeyへ切替え、セッション/サイドバー挙動とペースト処理等を調整した。 Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant User as "User"
participant DockView as "DockView (UI)"
participant Controller as "DockViewController"
participant Terminal as "TerminalView (tab)"
participant SessionMgr as "SessionManager"
User->>DockView: ドラッグ&ドロップでタブを移動/分割
DockView->>Controller: splitLeaf/ moveTabToLeaf/ addTabToLeaf
Controller->>Controller: 更新(root tree, focusedLeafId)
Controller-->>DockView: onChanged / onFocusChanged
DockView->>Terminal: paneBuilder(tabIndex,... ) をレンダリング
User->>Terminal: クリックでアクティブ化
Terminal->>Controller: アクティブ化イベント (via onFocusChanged)
User->>Terminal: クリップボード貼付け
Terminal->>Terminal: terminal.paste(text) を実行
SessionMgr-->>Terminal: セッション作成/接続ライフサイクル管理
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Important Merge conflicts detected (Beta)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment Tip CodeRabbit can use Trivy to scan for security misconfigurations and secrets in Infrastructure as Code files.Add a .trivyignore file to your project to customize which findings Trivy reports. |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@lib/screens/terminal_screen.dart`:
- Around line 854-858: The current implicit focus request using
FocusScope.of(context).requestFocus() depends on traversal behavior; replace it
with an explicit focus lookup by calling Focus.of(context, skipTraversal:
true)?.requestFocus() when using tab.terminalKey.currentContext to ensure the
terminal's focus node is targeted; alternatively (if you prefer exposing the
node) make TerminalViewState expose its _focusNode as a public field and type
terminalKey as GlobalKey<TerminalViewState> so you can call
terminalKey.currentState!.focusNode.requestFocus()—prefer the Focus.of approach
(use Focus.of(context, skipTraversal: true)?.requestFocus()) and update the code
references around tab.terminalKey.currentContext and
CustomTextEdit/TerminalViewState accordingly.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 6a1f7b2d-ec08-4546-afe0-233058866d69
📒 Files selected for processing (1)
lib/screens/terminal_screen.dart
| // Re-focus terminal to open keyboard | ||
| final context = tab.terminalKey.currentContext; | ||
| if (context != null) { | ||
| FocusScope.of(context).requestFocus(); | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
Flutter FocusScope.of(context).requestFocus() without arguments behavior
💡 Result:
FocusScope.of(context).requestFocus() (no argument) asks the current FocusScopeNode itself to take primary focus. Internally it calls _doRequestFocus(findFirstFocus: true), meaning the scope will try to put focus on the “first focus” inside that scope (typically the previously-focused child if one exists, otherwise the first focusable descendant it can find). If nothing inside can take focus, the scope ends up focused. Focus change notifications are delivered in a microtask (can appear up to a frame later). [1], [2]
If your intent is to “remove focus / dismiss keyboard”, prefer FocusScope.of(context).unfocus() instead of relying on requestFocus() patterns. [3]
Sources:
[1] Flutter API: FocusNode.requestFocus (also used by FocusScopeNode) https://api.flutter.dev/flutter/widgets/FocusNode/requestFocus.html
[2] Flutter focus internals note on scopes requesting focus and finding first descendant https://flutter.megathink.com/interaction/focus
[3] Flutter docs: “Understanding Flutter’s keyboard focus system” (recommends unfocus) https://docs.flutter.dev/ui/interactivity/focus
🏁 Script executed:
#!/bin/bash
# Description: Check if TerminalViewState exposes a focusNode field and its visibility
# Search for focusNode field declaration in TerminalViewState
rg -n -A 2 -B 2 'class TerminalViewState' packages/xterm/lib/src/terminal_view.dart
# Check focusNode field visibility (late FocusNode _focusNode or late FocusNode focusNode)
rg -n 'FocusNode.*focusNode' packages/xterm/lib/src/terminal_view.dartRepository: 6m10cmUK/Themisto
Length of output: 342
🏁 Script executed:
#!/bin/bash
# Check terminalKey declaration and its type
rg -n 'terminalKey.*=' lib/screens/terminal_screen.dart | head -5
# Also search for the full terminalKey field definition
rg -n -A 1 'final.*terminalKey' lib/screens/terminal_screen.dartRepository: 6m10cmUK/Themisto
Length of output: 424
🏁 Script executed:
#!/bin/bash
# Examine TerminalView widget to understand focus structure
rg -n -A 10 'class TerminalView' packages/xterm/lib/src/terminal_view.dart | head -30
# Check if TerminalView wraps its focusNode in a Focus widget
rg -n 'Focus\(' packages/xterm/lib/src/terminal_view.dartRepository: 6m10cmUK/Themisto
Length of output: 775
🏁 Script executed:
#!/bin/bash
# Find and examine TerminalViewState's build method
rg -n -A 50 'Widget build\(BuildContext context\)' packages/xterm/lib/src/terminal_view.dart | head -80Repository: 6m10cmUK/Themisto
Length of output: 2025
🏁 Script executed:
#!/bin/bash
# Check how _focusNode is initialized and used
rg -n 'initState\|_focusNode' packages/xterm/lib/src/terminal_view.dart | head -20Repository: 6m10cmUK/Themisto
Length of output: 43
フォーカスリクエストの実装を明確化してください。
FocusScope.of(context).requestFocus()(引数なし)は、スコープ内の最初にフォーカス可能な子ノードを探してフォーカスするため、実装は機能しています。CustomTextEditがTerminalViewStateの最初にフォーカス可能なウィジェットであり、内部の_focusNodeを持つため、結果としてターミナルは正しくフォーカスされキーボードが開きます。
ただし、この実装は暗黙的な動作に依存しており、脆弱です。より明示的で保守しやすいアプローチを検討してください:
- Focus.of()を使用(推奨):
FocusScope.of(context).requestFocus()の代わりにFocus.of(context, skipTraversal: true)?.requestFocus()を使用する - TerminalViewStateを変更:focusNodeをpublicフィールドとして公開し、GlobalKeyを型付けする(ただしxtermnパッケージの変更が必要)
現在のコードは動作していますが、次のいずれかの方法で改善することをお勧めします。
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@lib/screens/terminal_screen.dart` around lines 854 - 858, The current
implicit focus request using FocusScope.of(context).requestFocus() depends on
traversal behavior; replace it with an explicit focus lookup by calling
Focus.of(context, skipTraversal: true)?.requestFocus() when using
tab.terminalKey.currentContext to ensure the terminal's focus node is targeted;
alternatively (if you prefer exposing the node) make TerminalViewState expose
its _focusNode as a public field and type terminalKey as
GlobalKey<TerminalViewState> so you can call
terminalKey.currentState!.focusNode.requestFocus()—prefer the Focus.of approach
(use Focus.of(context, skipTraversal: true)?.requestFocus()) and update the code
references around tab.terminalKey.currentContext and
CustomTextEdit/TerminalViewState accordingly.
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
lib/screens/terminal_screen.dart (1)
963-977:⚠️ Potential issue | 🟠 MajorTerminalViewへのfocusNode未渡しによるキーボード入力問題
TerminalViewにfocusNodeパラメータを渡していないため、TerminalViewStateは内部で独自の_focusNodeを作成します。これにより外部からのフォーカス制御が切断され、PR目的で報告されている「キーボード入力が受け付けられない」問題の原因となっている可能性があります。PRコメントで指摘されている「外部FocusNodeのダブル管理」問題と関連しています。
🔧 検討オプション
オプション1:
_TerminalTabにFocusNodeを復元し、TerminalViewに渡すclass _TerminalTab { // ... final GlobalKey terminalKey = GlobalKey(); final FocusNode focusNode = FocusNode(); // ... }child: TerminalView( tab.terminal, key: tab.terminalKey, focusNode: tab.focusNode, // 追加 // ... )オプション2:
GlobalKey<TerminalViewState>を使用して内部の_focusNodeにアクセス(ただし_focusNodeは private)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/screens/terminal_screen.dart` around lines 963 - 977, TerminalView is not receiving an external FocusNode so TerminalViewState creates its own private _focusNode, breaking external focus control and causing keyboard input issues; restore a FocusNode on the owning tab (add a FocusNode field to _TerminalTab) and pass that FocusNode into the TerminalView constructor (use tab.focusNode when building TerminalView alongside tab.terminal and tab.terminalKey), ensuring you do not create a second FocusNode elsewhere to avoid double-management of focus.
🧹 Nitpick comments (3)
lib/widgets/dock_view.dart (2)
52-64: 初期化後のfocusedLeafIdの整合性コンストラクタで
focusedLeafId = '0'を設定していますが、その後の操作(タブ移動、リーフ削除など)で整合性が崩れる可能性があります。focusedLeafIdが常に有効なリーフを指すことを保証するバリデーションの追加を検討してください。♻️ バリデーション追加の例
String? get safeFocusedLeafId { if (focusedLeafId == null) return null; if (_findLeaf(root, focusedLeafId!) != null) return focusedLeafId; // Fallback to first available leaf focusedLeafId = _firstLeaf(root)?.id; return focusedLeafId; }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/widgets/dock_view.dart` around lines 52 - 64, The constructor sets focusedLeafId = '0' but offers no validation after mutations; add a safe getter and validation logic to ensure focusedLeafId always references an existing leaf by checking the tree (use existing helpers like _findLeaf and _firstLeaf against root) and update focusedLeafId to a valid fallback when missing (e.g., set to the first available leaf's id or null). Implement this as either a safeFocusedLeafId getter or a private validateFocusedLeaf method invoked after operations that mutate the tree (e.g., in methods that move tabs or remove leaves) and use that validated value wherever focusedLeafId is consumed.
350-360: 分割比率の永続化を検討
onPanUpdateでリアルタイムにbranch.ratioを更新していますが、onChangedコールバック経由で親に通知されています。ウィンドウリサイズ後も比率が保持されることを確認してください。🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/widgets/dock_view.dart` around lines 350 - 360, The current onPanUpdate updates branch.ratio live but doesn't guarantee persistence across window resizes; modify the split-pane logic so branch.ratio is treated as the source of truth and persisted whenever the user finishes dragging (use onPanEnd on the GestureDetector to call widget.onChanged with the final ratio or otherwise save it), ensure layout rebuilds compute pane sizes from branch.ratio and availableSize (respecting _kMinPaneSize) rather than storing absolute pixel sizes, and make sure any window resize handler reads branch.ratio to recompute firstSize/secondSize so the ratio is preserved.lib/screens/host_list_screen.dart (1)
39-52: デスクトッププラットフォーム判定の共通化を検討してくださいロジックは正しいですが、
terminal_screen.dartの_isDesktopやcustom_text_edit.dartの_isDesktopPlatformと同様のパターンが重複しています。共通ユーティリティへの抽出を検討してください。♻️ 共通ユーティリティの提案
// lib/utils/platform_utils.dart import 'package:flutter/foundation.dart'; bool get isDesktopPlatform => defaultTargetPlatform == TargetPlatform.windows || defaultTargetPlatform == TargetPlatform.macOS || defaultTargetPlatform == TargetPlatform.linux;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/screens/host_list_screen.dart` around lines 39 - 52, Extract the repeated desktop-detection logic into a shared utility (e.g. a top-level getter isDesktopPlatform in a new lib/utils/platform_utils.dart) and replace the inline checks in HostListScreen's onTap (the local isDesktop), TerminalScreen's _isDesktop, and CustomTextEdit's _isDesktopPlatform with that common isDesktopPlatform getter; update imports where needed and use isDesktopPlatform in the MaterialPageRoute builder to choose TerminalScreen(host: host) vs SessionListScreen(host: host).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@lib/screens/terminal_screen.dart`:
- Around line 89-99: The _currentTab getter can throw RangeError when _tabs is
empty (e.g. when sessionName is null on desktop); update any code that accesses
_currentTab or _tabs[_currentIndex] (notably the _currentTab getter itself and
callers like _copySelection, _pasteClipboard, _acceptSuggestion) to first check
_tabs.isEmpty (or validate _currentIndex) and handle the empty state gracefully
(early return, no-op, or fallback UI behavior) so no direct index access occurs
when there are no tabs.
- Around line 1158-1164: The code attempts to access a non-existent focusNode on
_TerminalTab (same bug as line 543). Fix by either calling the tab's existing
focus API (e.g. use _tabs[_currentIndex].requestFocus() or
_tabs[_currentIndex].focus() if such a method exists) or add a FocusNode field
to the _TerminalTab class (e.g. final FocusNode focusNode) and ensure it's
initialized and used by the tab widget, then keep the call
_tabs[_currentIndex].focusNode.requestFocus(); update whichever approach matches
the rest of the codebase.
- Around line 542-545: The code still references a removed focusNode on
_TerminalTab causing a compile error; replace the focusNode usage with the new
terminalKey-based API: locate where _tabs, _currentIndex and the _TerminalTab
class are used and change the focus call from
_tabs[_currentIndex].focusNode.requestFocus() to using the tab's terminalKey
(e.g. access the tab's terminalKey.currentState or currentContext and call the
appropriate requestFocus method) ensuring null checks (?.) are applied so focus
is only requested when terminalKey is available.
In `@packages/xterm/lib/src/ui/custom_text_edit.dart`:
- Around line 182-183: The code sets TextInputConfiguration(viewId:
View.of(context).viewId) which requires Flutter >= 3.19.0; ensure the package
constraint in pubspec.yaml enforces Flutter 3.19.0 or newer (e.g., update the
sdk constraint or bump the Flutter SDK version) so View.of(context).viewId is
available, or gate the use of viewId behind a runtime/compile-time check and
fall back to omitting viewId if older Flutter must be supported; locate the
occurrence in TextInputConfiguration and update pubspec.yaml SDK constraint or
add version-guarding around View.of(context).viewId accordingly.
---
Outside diff comments:
In `@lib/screens/terminal_screen.dart`:
- Around line 963-977: TerminalView is not receiving an external FocusNode so
TerminalViewState creates its own private _focusNode, breaking external focus
control and causing keyboard input issues; restore a FocusNode on the owning tab
(add a FocusNode field to _TerminalTab) and pass that FocusNode into the
TerminalView constructor (use tab.focusNode when building TerminalView alongside
tab.terminal and tab.terminalKey), ensuring you do not create a second FocusNode
elsewhere to avoid double-management of focus.
---
Nitpick comments:
In `@lib/screens/host_list_screen.dart`:
- Around line 39-52: Extract the repeated desktop-detection logic into a shared
utility (e.g. a top-level getter isDesktopPlatform in a new
lib/utils/platform_utils.dart) and replace the inline checks in HostListScreen's
onTap (the local isDesktop), TerminalScreen's _isDesktop, and CustomTextEdit's
_isDesktopPlatform with that common isDesktopPlatform getter; update imports
where needed and use isDesktopPlatform in the MaterialPageRoute builder to
choose TerminalScreen(host: host) vs SessionListScreen(host: host).
In `@lib/widgets/dock_view.dart`:
- Around line 52-64: The constructor sets focusedLeafId = '0' but offers no
validation after mutations; add a safe getter and validation logic to ensure
focusedLeafId always references an existing leaf by checking the tree (use
existing helpers like _findLeaf and _firstLeaf against root) and update
focusedLeafId to a valid fallback when missing (e.g., set to the first available
leaf's id or null). Implement this as either a safeFocusedLeafId getter or a
private validateFocusedLeaf method invoked after operations that mutate the tree
(e.g., in methods that move tabs or remove leaves) and use that validated value
wherever focusedLeafId is consumed.
- Around line 350-360: The current onPanUpdate updates branch.ratio live but
doesn't guarantee persistence across window resizes; modify the split-pane logic
so branch.ratio is treated as the source of truth and persisted whenever the
user finishes dragging (use onPanEnd on the GestureDetector to call
widget.onChanged with the final ratio or otherwise save it), ensure layout
rebuilds compute pane sizes from branch.ratio and availableSize (respecting
_kMinPaneSize) rather than storing absolute pixel sizes, and make sure any
window resize handler reads branch.ratio to recompute firstSize/secondSize so
the ratio is preserved.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 89fe5a9d-3fd4-4a35-b96a-503ebbde464a
📒 Files selected for processing (7)
lib/screens/host_list_screen.dartlib/screens/terminal_screen.dartlib/widgets/dock_view.dartlib/widgets/split_view.dartpackages/xterm/lib/src/core/buffer/buffer.dartpackages/xterm/lib/src/terminal_view.dartpackages/xterm/lib/src/ui/custom_text_edit.dart
💤 Files with no reviewable changes (1)
- lib/widgets/split_view.dart
| if (widget.sessionName != null) { | ||
| _addTab(widget.sessionName!); | ||
| if (_isDesktop) { | ||
| _sidebarOpen = true; | ||
| _loadSidebarSessions(); | ||
| } | ||
| } else { | ||
| // Desktop: open with sidebar, no initial tab | ||
| _sidebarOpen = true; | ||
| _loadSidebarSessions(); | ||
| } |
There was a problem hiding this comment.
sessionName が null の場合のタブなし起動
デスクトップで sessionName が null の場合、サイドバーのみで起動しタブは追加されません。_tabs.isEmpty の状態で _currentTab getter にアクセスするとエラーになる可能性があります。
🔍 確認が必要な箇所
_currentTab getter (line 70) は _tabs[_currentIndex] を返しますが、_tabs が空の場合は RangeError が発生します。_tabs.isEmpty チェックが必要な箇所を確認してください:
_copySelection(line 725)_pasteClipboard(line 741)_acceptSuggestion(line 878)- etc.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@lib/screens/terminal_screen.dart` around lines 89 - 99, The _currentTab
getter can throw RangeError when _tabs is empty (e.g. when sessionName is null
on desktop); update any code that accesses _currentTab or _tabs[_currentIndex]
(notably the _currentTab getter itself and callers like _copySelection,
_pasteClipboard, _acceptSuggestion) to first check _tabs.isEmpty (or validate
_currentIndex) and handle the empty state gracefully (early return, no-op, or
fallback UI behavior) so no direct index access occurs when there are no tabs.
| if (_isDesktop && _currentIndex < _tabs.length) { | ||
| _tabs[_currentIndex].focusNode.requestFocus(); | ||
| } | ||
| return; |
There was a problem hiding this comment.
存在しない focusNode フィールドへの参照
_TerminalTab クラスから focusNode フィールドが削除されましたが、このコードは依然として tab.focusNode を参照しています。これはコンパイルエラーになります。
🐛 修正案
terminalKey を使用してフォーカスを要求する方法に変更:
if (_isDesktop && _currentIndex < _tabs.length) {
- _tabs[_currentIndex].focusNode.requestFocus();
+ final context = _tabs[_currentIndex].terminalKey.currentContext;
+ if (context != null) {
+ FocusScope.of(context).requestFocus();
+ }
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (_isDesktop && _currentIndex < _tabs.length) { | |
| _tabs[_currentIndex].focusNode.requestFocus(); | |
| } | |
| return; | |
| if (_isDesktop && _currentIndex < _tabs.length) { | |
| final context = _tabs[_currentIndex].terminalKey.currentContext; | |
| if (context != null) { | |
| FocusScope.of(context).requestFocus(); | |
| } | |
| } | |
| return; |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@lib/screens/terminal_screen.dart` around lines 542 - 545, The code still
references a removed focusNode on _TerminalTab causing a compile error; replace
the focusNode usage with the new terminalKey-based API: locate where _tabs,
_currentIndex and the _TerminalTab class are used and change the focus call from
_tabs[_currentIndex].focusNode.requestFocus() to using the tab's terminalKey
(e.g. access the tab's terminalKey.currentState or currentContext and call the
appropriate requestFocus method) ensuring null checks (?.) are applied so focus
is only requested when terminalKey is available.
| final leaf = _dockController!.focusedLeaf(); | ||
| if (leaf != null && leaf.tabIndices.isNotEmpty) { | ||
| setState(() => _currentIndex = leaf.activeTabIndex); | ||
| if (_currentIndex >= 0 && _currentIndex < _tabs.length) { | ||
| _tabs[_currentIndex].focusNode.requestFocus(); | ||
| } | ||
| } |
There was a problem hiding this comment.
同様の focusNode 参照エラー
Line 543と同じ問題です。_TerminalTab に focusNode フィールドは存在しません。
🐛 修正案
if (_currentIndex >= 0 && _currentIndex < _tabs.length) {
- _tabs[_currentIndex].focusNode.requestFocus();
+ final context = _tabs[_currentIndex].terminalKey.currentContext;
+ if (context != null) {
+ FocusScope.of(context).requestFocus();
+ }
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| final leaf = _dockController!.focusedLeaf(); | |
| if (leaf != null && leaf.tabIndices.isNotEmpty) { | |
| setState(() => _currentIndex = leaf.activeTabIndex); | |
| if (_currentIndex >= 0 && _currentIndex < _tabs.length) { | |
| _tabs[_currentIndex].focusNode.requestFocus(); | |
| } | |
| } | |
| final leaf = _dockController!.focusedLeaf(); | |
| if (leaf != null && leaf.tabIndices.isNotEmpty) { | |
| setState(() => _currentIndex = leaf.activeTabIndex); | |
| if (_currentIndex >= 0 && _currentIndex < _tabs.length) { | |
| final context = _tabs[_currentIndex].terminalKey.currentContext; | |
| if (context != null) { | |
| FocusScope.of(context).requestFocus(); | |
| } | |
| } | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@lib/screens/terminal_screen.dart` around lines 1158 - 1164, The code attempts
to access a non-existent focusNode on _TerminalTab (same bug as line 543). Fix
by either calling the tab's existing focus API (e.g. use
_tabs[_currentIndex].requestFocus() or _tabs[_currentIndex].focus() if such a
method exists) or add a FocusNode field to the _TerminalTab class (e.g. final
FocusNode focusNode) and ensure it's initialized and used by the tab widget,
then keep the call _tabs[_currentIndex].focusNode.requestFocus(); update
whichever approach matches the rest of the codebase.
| final config = TextInputConfiguration( | ||
| viewId: View.of(context).viewId, |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
Flutter TextInputConfiguration viewId parameter minimum version requirement
💡 Result:
The viewId parameter in Flutter's TextInputConfiguration was added in framework pull request #145708, merged to master on 2024-03-28. The corresponding engine support was added in PR #51099, merged on 2024-03-29. This feature became available in the first stable Flutter release after these merges, which is Flutter 3.19.0 (stable release around April 2024), as earlier stable versions like 3.19 beta predate the merge, and 3.19 release notes confirm framework updates post-merge. The API docs confirm viewId as int? viewId with default null, usable from this version onward. No explicit minimum version is stated in docs, but usage requires Flutter >= 3.19.0.
Citations:
- 1: Add
viewIdtoTextInputConfigurationflutter/flutter#145708 - 2: https://api.flutter.dev/flutter/services/TextInputConfiguration/viewId.html
- 3: https://api.flutter.dev/flutter/services/TextInputConfiguration/TextInputConfiguration.html
- 4: https://api.flutter.dev/flutter/services/TextInputConfiguration-class.html
- 5: https://api.flutter.dev/flutter/widgets/EditableTextState/textInputConfiguration.html
- 6: [web] Use viewId for text editing flutter-team-archive/engine#51099
- 7: https://docs.flutter.dev/release/release-notes/release-notes-3.19.0
- 8: https://github.com/flutter/flutter/releases
- 9: https://flutter.googlesource.com/mirrors/flutter/+/refs/tags/3.19.3
viewId パラメータの Flutter バージョン要件を確認してください
viewId は マルチビュー/マルチウィンドウのサポートに必要ですが、このパラメータは Flutter 3.19.0 以降 で利用可能です。プロジェクトの pubspec.yaml の Flutter バージョン制約が 3.19.0 以上に設定されていることを確認してください。
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/xterm/lib/src/ui/custom_text_edit.dart` around lines 182 - 183, The
code sets TextInputConfiguration(viewId: View.of(context).viewId) which requires
Flutter >= 3.19.0; ensure the package constraint in pubspec.yaml enforces
Flutter 3.19.0 or newer (e.g., update the sdk constraint or bump the Flutter SDK
version) so View.of(context).viewId is available, or gate the use of viewId
behind a runtime/compile-time check and fall back to omitting viewId if older
Flutter must be supported; locate the occurrence in TextInputConfiguration and
update pubspec.yaml SDK constraint or add version-guarding around
View.of(context).viewId accordingly.
現状
Windows版で日本語入力(IME)ができない。英語入力は動く。
原因の分析
packages/xterm/lib/src/ui/custom_text_edit.dartの_onKeyEventを修正済み(148-157行):KeyEventResult.ignoredを返す確認すべきこと
flutter runして日本語入力を試す_onKeyEventにprintを入れて、印字可能文字でignoredが返ってるか確認updateEditingValueにprintを入れて、IMEから値が来てるか確認_onInsertにprintを入れて、テキストが届いてるか確認ファイル構成
キーイベントの流れ
Android側への影響
_isDesktopPlatformフラグで分岐してるのでAndroidには影響なし。その他メモ
feature/autocompleteはmasterにmerge済み(コマンド履歴補完)android-v1.0.10windows-v1.0.0(IME修正入りだが未確認)flutter runしてデバッグするのが一番早いSummary by CodeRabbit
リリース ノート
新機能
不具合修正
リファクタリング