Skip to content

Commit 384800b

Browse files
authored
Fix right clicking a field to focus (#103228)
1 parent 0f23e96 commit 384800b

File tree

4 files changed

+137
-14
lines changed

4 files changed

+137
-14
lines changed

packages/flutter/lib/src/rendering/editable.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1958,6 +1958,7 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin,
19581958
extentOffset: extentOffset,
19591959
affinity: fromPosition.affinity,
19601960
);
1961+
19611962
_setSelection(newSelection, cause);
19621963
}
19631964

packages/flutter/lib/src/widgets/editable_text.dart

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2441,6 +2441,23 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
24412441
_selectionOverlay?.updateForScroll();
24422442
}
24432443

2444+
void _createSelectionOverlay() {
2445+
_selectionOverlay = TextSelectionOverlay(
2446+
clipboardStatus: _clipboardStatus,
2447+
context: context,
2448+
value: _value,
2449+
debugRequiredFor: widget,
2450+
toolbarLayerLink: _toolbarLayerLink,
2451+
startHandleLayerLink: _startHandleLayerLink,
2452+
endHandleLayerLink: _endHandleLayerLink,
2453+
renderObject: renderEditable,
2454+
selectionControls: widget.selectionControls,
2455+
selectionDelegate: this,
2456+
dragStartBehavior: widget.dragStartBehavior,
2457+
onSelectionHandleTapped: widget.onSelectionHandleTapped,
2458+
);
2459+
}
2460+
24442461
@pragma('vm:notify-debugger-on-exception')
24452462
void _handleSelectionChanged(TextSelection selection, SelectionChangedCause? cause) {
24462463
// We return early if the selection is not valid. This can happen when the
@@ -2478,20 +2495,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
24782495
_selectionOverlay = null;
24792496
} else {
24802497
if (_selectionOverlay == null) {
2481-
_selectionOverlay = TextSelectionOverlay(
2482-
clipboardStatus: _clipboardStatus,
2483-
context: context,
2484-
value: _value,
2485-
debugRequiredFor: widget,
2486-
toolbarLayerLink: _toolbarLayerLink,
2487-
startHandleLayerLink: _startHandleLayerLink,
2488-
endHandleLayerLink: _endHandleLayerLink,
2489-
renderObject: renderEditable,
2490-
selectionControls: widget.selectionControls,
2491-
selectionDelegate: this,
2492-
dragStartBehavior: widget.dragStartBehavior,
2493-
onSelectionHandleTapped: widget.onSelectionHandleTapped,
2494-
);
2498+
_createSelectionOverlay();
24952499
} else {
24962500
_selectionOverlay!.update(_value);
24972501
}
@@ -2943,6 +2947,18 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
29432947
if (shouldShowCaret) {
29442948
_scheduleShowCaretOnScreen(withAnimation: true);
29452949
}
2950+
2951+
// Even if the value doesn't change, it may be necessary to focus and build
2952+
// the selection overlay. For example, this happens when right clicking an
2953+
// unfocused field that previously had a selection in the same spot.
2954+
if (value == textEditingValue) {
2955+
if (!widget.focusNode.hasFocus) {
2956+
widget.focusNode.requestFocus();
2957+
_createSelectionOverlay();
2958+
}
2959+
return;
2960+
}
2961+
29462962
_formatAndSetValue(value, cause, userInteraction: true);
29472963
}
29482964

packages/flutter/test/cupertino/text_field_test.dart

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5663,4 +5663,56 @@ void main() {
56635663
variant: TargetPlatformVariant.all(),
56645664
skip: isContextMenuProvidedByPlatform, // [intended] only applies to platforms where we supply the context menu.
56655665
);
5666+
5667+
testWidgets('Can right click to focus multiple times', (WidgetTester tester) async {
5668+
// Regression test for https://github.com/flutter/flutter/pull/103228
5669+
final FocusNode focusNode1 = FocusNode();
5670+
final FocusNode focusNode2 = FocusNode();
5671+
final UniqueKey key1 = UniqueKey();
5672+
final UniqueKey key2 = UniqueKey();
5673+
await tester.pumpWidget(
5674+
CupertinoApp(
5675+
home: Column(
5676+
children: <Widget>[
5677+
CupertinoTextField(
5678+
key: key1,
5679+
focusNode: focusNode1,
5680+
),
5681+
CupertinoTextField(
5682+
key: key2,
5683+
focusNode: focusNode2,
5684+
),
5685+
],
5686+
),
5687+
),
5688+
);
5689+
5690+
// Interact with the field to establish the input connection.
5691+
await tester.tapAt(
5692+
tester.getCenter(find.byKey(key1)),
5693+
buttons: kSecondaryMouseButton,
5694+
);
5695+
await tester.pump();
5696+
5697+
expect(focusNode1.hasFocus, isTrue);
5698+
expect(focusNode2.hasFocus, isFalse);
5699+
5700+
await tester.tapAt(
5701+
tester.getCenter(find.byKey(key2)),
5702+
buttons: kSecondaryMouseButton,
5703+
);
5704+
await tester.pump();
5705+
5706+
expect(focusNode1.hasFocus, isFalse);
5707+
expect(focusNode2.hasFocus, isTrue);
5708+
5709+
await tester.tapAt(
5710+
tester.getCenter(find.byKey(key1)),
5711+
buttons: kSecondaryMouseButton,
5712+
);
5713+
await tester.pump();
5714+
5715+
expect(focusNode1.hasFocus, isTrue);
5716+
expect(focusNode2.hasFocus, isFalse);
5717+
});
56665718
}

packages/flutter/test/material/text_field_test.dart

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11399,4 +11399,58 @@ void main() {
1139911399
variant: TargetPlatformVariant.all(),
1140011400
skip: isContextMenuProvidedByPlatform, // [intended] only applies to platforms where we supply the context menu.
1140111401
);
11402+
11403+
testWidgets('Can right click to focus multiple times', (WidgetTester tester) async {
11404+
// Regression test for https://github.com/flutter/flutter/pull/103228
11405+
final FocusNode focusNode1 = FocusNode();
11406+
final FocusNode focusNode2 = FocusNode();
11407+
final UniqueKey key1 = UniqueKey();
11408+
final UniqueKey key2 = UniqueKey();
11409+
await tester.pumpWidget(
11410+
MaterialApp(
11411+
home: Material(
11412+
child: Column(
11413+
children: <Widget>[
11414+
TextField(
11415+
key: key1,
11416+
focusNode: focusNode1,
11417+
),
11418+
TextField(
11419+
key: key2,
11420+
focusNode: focusNode2,
11421+
),
11422+
],
11423+
),
11424+
),
11425+
),
11426+
);
11427+
11428+
// Interact with the field to establish the input connection.
11429+
await tester.tapAt(
11430+
tester.getCenter(find.byKey(key1)),
11431+
buttons: kSecondaryButton,
11432+
);
11433+
await tester.pump();
11434+
11435+
expect(focusNode1.hasFocus, isTrue);
11436+
expect(focusNode2.hasFocus, isFalse);
11437+
11438+
await tester.tapAt(
11439+
tester.getCenter(find.byKey(key2)),
11440+
buttons: kSecondaryButton,
11441+
);
11442+
await tester.pump();
11443+
11444+
expect(focusNode1.hasFocus, isFalse);
11445+
expect(focusNode2.hasFocus, isTrue);
11446+
11447+
await tester.tapAt(
11448+
tester.getCenter(find.byKey(key1)),
11449+
buttons: kSecondaryButton,
11450+
);
11451+
await tester.pump();
11452+
11453+
expect(focusNode1.hasFocus, isTrue);
11454+
expect(focusNode2.hasFocus, isFalse);
11455+
});
1140211456
}

0 commit comments

Comments
 (0)