Unverified Commit d9a69e3b authored by Justin McCandless's avatar Justin McCandless Committed by GitHub

Desktop keys: up/down + line modifier (#74425)

up/down arrows + cmd (optionally + shift) works on desktop to jump selection to beginning/end of field
parent 35b9288e
...@@ -712,33 +712,57 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin { ...@@ -712,33 +712,57 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin {
// case where the user moves the cursor to the end or beginning of the text // case where the user moves the cursor to the end or beginning of the text
// and then back up or down. // and then back up or down.
if (downArrow || upArrow) { if (downArrow || upArrow) {
// The caret offset gives a location in the upper left hand corner of if (lineModifier) {
// the caret so the middle of the line above is a half line above that if (upArrow) {
// point and the line below is 1.5 lines below that point. // Extend the selection to the beginning of the field.
final double preferredLineHeight = _textPainter.preferredLineHeight; final int upperOffset = math.max(0, math.max(
final double verticalOffset = upArrow ? -0.5 * preferredLineHeight : 1.5 * preferredLineHeight; newSelection.baseOffset,
newSelection.extentOffset,
final Offset caretOffset = _textPainter.getOffsetForCaret(TextPosition(offset: newSelection.extentOffset), _caretPrototype); ));
final Offset caretOffsetTranslated = caretOffset.translate(0.0, verticalOffset); newSelection = TextSelection(
final TextPosition position = _textPainter.getPositionForOffset(caretOffsetTranslated); baseOffset: shift ? upperOffset : 0,
extentOffset: 0,
// To account for the possibility where the user vertically highlights );
// all the way to the top or bottom of the text, we hold the previous } else {
// cursor location. This allows us to restore to this position in the // Extend the selection to the end of the field.
// case that the user wants to unhighlight some text. final int lowerOffset = math.max(0, math.min(
if (position.offset == newSelection.extentOffset) { newSelection.baseOffset,
if (downArrow) { newSelection.extentOffset,
newSelection = newSelection.copyWith(extentOffset: _plainText.length); ));
} else if (upArrow) { newSelection = TextSelection(
newSelection = newSelection.copyWith(extentOffset: 0); baseOffset: shift ? lowerOffset : _plainText.length,
extentOffset: _plainText.length,
);
} }
_wasSelectingVerticallyWithKeyboard = shift;
} else if (_wasSelectingVerticallyWithKeyboard && shift) {
newSelection = newSelection.copyWith(extentOffset: _cursorResetLocation);
_wasSelectingVerticallyWithKeyboard = false;
} else { } else {
newSelection = newSelection.copyWith(extentOffset: position.offset); // The caret offset gives a location in the upper left hand corner of
_cursorResetLocation = newSelection.extentOffset; // the caret so the middle of the line above is a half line above that
// point and the line below is 1.5 lines below that point.
final double preferredLineHeight = _textPainter.preferredLineHeight;
final double verticalOffset = upArrow ? -0.5 * preferredLineHeight : 1.5 * preferredLineHeight;
final Offset caretOffset = _textPainter.getOffsetForCaret(TextPosition(offset: newSelection.extentOffset), _caretPrototype);
final Offset caretOffsetTranslated = caretOffset.translate(0.0, verticalOffset);
final TextPosition position = _textPainter.getPositionForOffset(caretOffsetTranslated);
// To account for the possibility where the user vertically highlights
// all the way to the top or bottom of the text, we hold the previous
// cursor location. This allows us to restore to this position in the
// case that the user wants to unhighlight some text.
if (position.offset == newSelection.extentOffset) {
if (downArrow) {
newSelection = newSelection.copyWith(extentOffset: _plainText.length);
} else if (upArrow) {
newSelection = newSelection.copyWith(extentOffset: 0);
}
_wasSelectingVerticallyWithKeyboard = shift;
} else if (_wasSelectingVerticallyWithKeyboard && shift) {
newSelection = newSelection.copyWith(extentOffset: _cursorResetLocation);
_wasSelectingVerticallyWithKeyboard = false;
} else {
newSelection = newSelection.copyWith(extentOffset: position.offset);
_cursorResetLocation = newSelection.extentOffset;
}
} }
} }
......
...@@ -4167,6 +4167,144 @@ void main() { ...@@ -4167,6 +4167,144 @@ void main() {
reason: 'on $platform', reason: 'on $platform',
); );
// Jump to end.
await sendKeys(
tester,
<LogicalKeyboardKey>[
LogicalKeyboardKey.arrowDown,
],
shift: false,
lineModifier: true,
platform: platform,
);
expect(
selection,
equals(
const TextSelection.collapsed(
offset: testText.length,
affinity: TextAffinity.downstream,
),
),
reason: 'on $platform',
);
expect(controller.text, equals(testText), reason: 'on $platform');
// Jump to start.
await sendKeys(
tester,
<LogicalKeyboardKey>[
LogicalKeyboardKey.arrowUp,
],
shift: false,
lineModifier: true,
platform: platform,
);
expect(
selection,
equals(
const TextSelection.collapsed(
offset: 0,
affinity: TextAffinity.downstream,
),
),
reason: 'on $platform',
);
expect(controller.text, equals(testText), reason: 'on $platform');
// Move forward a few letters
await sendKeys(
tester,
<LogicalKeyboardKey>[
LogicalKeyboardKey.arrowRight,
LogicalKeyboardKey.arrowRight,
LogicalKeyboardKey.arrowRight,
],
shift: false,
lineModifier: false,
platform: platform,
);
expect(
selection,
equals(
const TextSelection.collapsed(
offset: 3,
affinity: TextAffinity.downstream,
),
),
reason: 'on $platform',
);
// Select to end.
await sendKeys(
tester,
<LogicalKeyboardKey>[
LogicalKeyboardKey.arrowDown,
],
shift: true,
lineModifier: true,
platform: platform,
);
expect(
selection,
equals(
const TextSelection(
baseOffset: 3,
extentOffset: testText.length,
affinity: TextAffinity.downstream,
),
),
reason: 'on $platform',
);
// Select to start, which extends the selection.
await sendKeys(
tester,
<LogicalKeyboardKey>[
LogicalKeyboardKey.arrowUp,
],
shift: true,
lineModifier: true,
platform: platform,
);
expect(
selection,
equals(
const TextSelection(
baseOffset: testText.length,
extentOffset: 0,
affinity: TextAffinity.downstream,
),
),
reason: 'on $platform',
);
// Move to start again.
await sendKeys(
tester,
<LogicalKeyboardKey>[
LogicalKeyboardKey.arrowUp,
],
shift: false,
lineModifier: false,
platform: platform,
);
expect(
selection,
equals(
const TextSelection.collapsed(
offset: 0,
affinity: TextAffinity.downstream,
),
),
reason: 'on $platform',
);
// Jump forward three words. // Jump forward three words.
await sendKeys( await sendKeys(
tester, tester,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment