浏览代码

update editable

/main
fzhangtj 6 年前
当前提交
dda01af9
共有 8 个文件被更改,包括 544 次插入499 次删除
  1. 1
      Runtime/editor/editor_window.cs
  2. 490
      Runtime/rendering/editable.cs
  3. 26
      Runtime/service/keyboard.cs
  4. 52
      Runtime/service/text_input.cs
  5. 228
      Runtime/widgets/editable_text.cs
  6. 82
      Runtime/service/raw_keyboard.cs
  7. 11
      Runtime/service/text_input_utils.cs.meta
  8. 153
      Runtime/service/text_input_utils.cs

1
Runtime/editor/editor_window.cs


}
}
RawKeyboard.instance._handleKeyEvent(Event.current);
TextInput.OnGUI();
}

490
Runtime/rendering/editable.cs


return $"Point: {this.point}, Direction: {this.direction}";
}
}
/*
this._doubleTapGesture = new DoubleTapGestureRecognizer(this.rendererBindings.rendererBinding);
this._doubleTapGesture.onDoubleTap = () => { Debug.Log("onDoubleTap"); };*/
public class RenderEditable : RenderBox {
public static readonly char obscuringCharacter = '•';

TextPainter _textPainter;
Color _cursorColor;
bool _hasFocus;
int? _maxLines;
Color _selectionColor;
ViewportOffset _offset;

TextAlign textAlign = TextAlign.left, float textScaleFactor = 1.0f, Color cursorColor = null,
bool? hasFocus = null, int? maxLines = 1, Color selectionColor = null,
TextSelection selection = null, bool obscureText = false, SelectionChangedHandler onSelectionChanged = null,
CaretChangedHandler onCaretChanged = null, bool ignorePointer = false) {
CaretChangedHandler onCaretChanged = null, bool ignorePointer = false,
TextSelectionDelegate textSelectionDelegate = null) {
D.assert(textSelectionDelegate != null);
this._textPainter = new TextPainter(text: text, textAlign: textAlign, textDirection: textDirection,
textScaleFactor: textScaleFactor);
this._cursorColor = cursorColor;

this.ignorePointer = ignorePointer;
this.onCaretChanged = onCaretChanged;
this.onSelectionChanged = onSelectionChanged;
this.textSelectionDelegate = textSelectionDelegate;
D.assert(this._maxLines == null || this._maxLines > 0);
D.assert(this._showCursor != null);

}
}
public TextSelectionDelegate textSelectionDelegate;
int _extentOffset = -1;
int _baseOffset = -1;
int _previousCursorLocation;
bool _resetCursor = false;
void _handleKeyEvent(RawKeyEvent keyEvent) {
if (keyEvent is RawKeyUpEvent) {
return;
}
if (this.selection.isCollapsed) {
this._extentOffset = this.selection.extentOffset;
this._baseOffset = this.selection.baseOffset;
}
KeyCode pressedKeyCode = keyEvent.data.unityEvent.keyCode;
int modifiers = (int) keyEvent.data.unityEvent.modifiers;
bool shift = (modifiers & (int)EventModifiers.Shift) > 0;
bool ctrl = (modifiers & (int)EventModifiers.Control) > 0;
bool alt = (modifiers & (int)EventModifiers.Alt) > 0;
bool cmd = (modifiers & (int)EventModifiers.Command) > 0;
bool rightArrow = pressedKeyCode == KeyCode.RightArrow;
bool leftArrow = pressedKeyCode == KeyCode.LeftArrow;
bool upArrow = pressedKeyCode == KeyCode.UpArrow;
bool downArrow = pressedKeyCode == KeyCode.DownArrow;
bool arrow = leftArrow || rightArrow || upArrow || downArrow;
bool aKey = pressedKeyCode == KeyCode.A;
bool xKey = pressedKeyCode == KeyCode.X;
bool vKey = pressedKeyCode == KeyCode.V;
bool cKey = pressedKeyCode == KeyCode.C;
bool del = pressedKeyCode == KeyCode.Delete;
bool backDel = pressedKeyCode == KeyCode.Backspace;
bool isMac = SystemInfo.operatingSystemFamily == OperatingSystemFamily.MacOSX;
if (arrow) {
int newOffset = this._extentOffset;
var word = (isMac && alt) || ctrl;
if (word) {
newOffset = this._handleControl(rightArrow, leftArrow, word, newOffset);
}
newOffset = this._handleHorizontalArrows(rightArrow, leftArrow, shift, newOffset);
if (downArrow || upArrow)
newOffset = this._handleVerticalArrows(upArrow, downArrow, shift, newOffset);
newOffset = this._handleShift(rightArrow, leftArrow, shift, newOffset);
this._extentOffset = newOffset;
} else if ((ctrl || (isMac && cmd)) && (xKey || vKey || cKey || aKey)) {
this._handleShortcuts(pressedKeyCode);
}
if (del || backDel) {
this._handleDelete(backDel);
}
}
int _handleControl(bool rightArrow, bool leftArrow, bool ctrl, int newOffset) {
// If control is pressed, we will decide which way to look for a word
// based on which arrow is pressed.
if (leftArrow && this._extentOffset > 2) {
TextSelection textSelection = this._selectWordAtOffset(new TextPosition(offset: this._extentOffset - 2));
newOffset = textSelection.baseOffset + 1;
} else if (rightArrow && this._extentOffset < this.text.text.Length - 2) {
TextSelection textSelection = this._selectWordAtOffset(new TextPosition(offset: this._extentOffset + 1));
newOffset = textSelection.extentOffset - 1;
}
return newOffset;
}
int _handleHorizontalArrows(bool rightArrow, bool leftArrow, bool shift, int newOffset) {
if (rightArrow && this._extentOffset < this.text.text.Length) {
newOffset += 1;
if (shift) {
this._previousCursorLocation += 1;
}
}
if (leftArrow && this._extentOffset > 0) {
newOffset -= 1;
if (shift) {
this._previousCursorLocation -= 1;
}
}
return newOffset;
}
int _handleVerticalArrows(bool upArrow, bool downArrow, bool shift, int newOffset) {
float plh = this._textPainter.preferredLineHeight;
float verticalOffset = upArrow ? -0.5f * plh : 1.5f * plh;
Offset caretOffset = this._textPainter.getOffsetForCaret(new TextPosition(offset: this._extentOffset), this._caretPrototype);
Offset caretOffsetTranslated = caretOffset.translate(0.0f, verticalOffset);
TextPosition position = this._textPainter.getPositionForOffset(caretOffsetTranslated);
if (position.offset == this._extentOffset) {
if (downArrow)
newOffset = this.text.text.Length;
else if (upArrow)
newOffset = 0;
this._resetCursor = shift;
} else if (this._resetCursor && shift) {
newOffset = this._previousCursorLocation;
this._resetCursor = false;
} else {
newOffset = position.offset;
this._previousCursorLocation = newOffset;
}
return newOffset;
}
int _handleShift(bool rightArrow, bool leftArrow, bool shift, int newOffset) {
if (this.onSelectionChanged == null)
return newOffset;
if (shift) {
if (this._baseOffset < newOffset) {
this.onSelectionChanged(
new TextSelection(
baseOffset: this._baseOffset,
extentOffset: newOffset
),
this,
SelectionChangedCause.keyboard
);
} else {
this.onSelectionChanged(
new TextSelection(
baseOffset: newOffset,
extentOffset: this._baseOffset
),
this,
SelectionChangedCause.keyboard
);
}
} else {
if (!this.selection.isCollapsed) {
if (leftArrow)
newOffset = this._baseOffset < this._extentOffset ? this._baseOffset : this._extentOffset;
else if (rightArrow)
newOffset = this._baseOffset > this._extentOffset ? this._baseOffset : this._extentOffset;
}
this.onSelectionChanged(
TextSelection.fromPosition(
new TextPosition(
offset: newOffset
)
),
this,
SelectionChangedCause.keyboard
);
}
return newOffset;
}
void _handleShortcuts(KeyCode pressedKeyCode) {
switch (pressedKeyCode) {
case KeyCode.C:
if (!this.selection.isCollapsed) {
Clipboard.setData(
new ClipboardData(text: this.selection.textInside(this.text.text)));
}
break;
case KeyCode.X:
if (!this.selection.isCollapsed) {
Clipboard.setData(
new ClipboardData(text: this.selection.textInside(this.text.text)));
this.textSelectionDelegate.textEditingValue = new TextEditingValue(
text: this.selection.textBefore(this.text.text)
+ this.selection.textAfter(this.text.text),
selection: TextSelection.collapsed(offset: this.selection.start)
);
}
break;
case KeyCode.V:
TextEditingValue value = this.textSelectionDelegate.textEditingValue;
Clipboard.getData(Clipboard.kTextPlain).Then(data => {
if (data != null) {
this.textSelectionDelegate.textEditingValue = new TextEditingValue(
text: value.selection.textBefore(value.text)
+ data.text
+ value.selection.textAfter(value.text),
selection: TextSelection.collapsed(
offset: value.selection.start + data.text.Length
)
);
}
});
break;
case KeyCode.A:
this._baseOffset = 0;
this._extentOffset = this.textSelectionDelegate.textEditingValue.text.Length;
this.onSelectionChanged(
new TextSelection(
baseOffset: 0,
extentOffset: this.textSelectionDelegate.textEditingValue.text.Length
),
this,
SelectionChangedCause.keyboard
);
break;
default:
D.assert(false);
break;
}
}
void _handleDelete(bool backDel) {
var selection = this.selection;
if (backDel && selection.isCollapsed) {
if (selection.start <= 0) {
return;
}
selection = TextSelection.collapsed(selection.start - 1, selection.affinity);
}
if (selection.textAfter(this.text.text).isNotEmpty()) {
this.textSelectionDelegate.textEditingValue = new TextEditingValue(
text: selection.textBefore(this.text.text)
+ selection.textAfter(this.text.text).Substring(1),
selection: TextSelection.collapsed(offset: selection.start)
);
} else {
this.textSelectionDelegate.textEditingValue = new TextEditingValue(
text: selection.textBefore(this.text.text),
selection: TextSelection.collapsed(offset: selection.start)
);
}
}
protected void markNeedsTextLayout() {
this._textLayoutLastWidth = null;
this.markNeedsLayout();
}
public TextSpan text {
get { return this._textPainter.text; }
set {

}
}
public ValueNotifier<bool> ShowCursor {
public ValueNotifier<bool> showCursor {
get { return this._showCursor; }
set {
D.assert(value != null);

}
}
bool _hasFocus;
bool _listenerAttached = false;
public bool hasFocus {
get { return this._hasFocus; }
set {

this._hasFocus = value;
if (this._hasFocus) {
D.assert(!this._listenerAttached);
RawKeyboard.instance.addListener(this._handleKeyEvent);
this._listenerAttached = true;
}
else {
D.assert(this._listenerAttached);
RawKeyboard.instance.removeListener(this._handleKeyEvent);
this._listenerAttached = false;
}
this.markNeedsSemanticsUpdate();
}
}

this.markNeedsLayout();
}
}
float _cursorWidth = 1.0f;
public ValueNotifier<bool> showCursor {
get { return this._showCursor; }
set {
D.assert(value != null);
if (this._showCursor == value) {
public float cursorWidth {
get { return this._cursorWidth; }
set {
if (this._cursorWidth == value)
}
if (this.attached) {
this._showCursor.removeListener(this.markNeedsPaint);
}
this._showCursor = value;
if (this.attached) {
this._showCursor.addListener(this.markNeedsPaint);
}
this.markNeedsPaint();
this._cursorWidth = value;
this.markNeedsLayout();
}
}
Radius _cursorRadius;
public Radius cursorRadius {
get { return this._cursorRadius; }
set {
if (this._cursorRadius == value)
return;
this._cursorRadius = value;
this.markNeedsLayout();
}
}
bool _enableInteractiveSelection;
public bool enableInteractiveSelection {
get { return this._enableInteractiveSelection; }
set {
if (this._enableInteractiveSelection == value)
return;
this._enableInteractiveSelection = value;
this.markNeedsTextLayout();
this.markNeedsSemanticsUpdate();
}
}

public override void detach() {
this._offset.removeListener(this.markNeedsLayout);
this._showCursor.removeListener(this.markNeedsPaint);
if (this._listenerAttached) {
RawKeyboard.instance.removeListener(this._handleKeyEvent);
}
base.detach();
}

this._longPress.addPointer((PointerDownEvent) evt);
}
}
public void handleTapDown(TapDownDetails details) {
this._lastTapDownPosition = details.globalPosition - this._paintOffset;
void handleTapDown(TapDownDetails details) {
this._lastTapDownPosition = details.globalPosition + - this._paintOffset;
this._selectForTap(this._lastTapDownPosition);
this.selectPosition(SelectionChangedCause.tap);
void _handleTapDown(TapDownDetails details) {
D.assert(!this.ignorePointer);
this.handleTapDown(details);
}
public void handleTap() {
this.selectPosition(cause: SelectionChangedCause.tap);
}
public void handleTap() {
this._layoutText(this.constraints.maxWidth);
D.assert(this._lastTapDownPosition != null);
if (Application.isMobilePlatform) {
this._selectForTap(this._lastTapDownPosition);
}
void _handleTap() {
D.assert(!this.ignorePointer);
this.handleTap();
void _handleDoubleTap(DoubleTapDetails details) {
D.assert(!this.ignorePointer);
this.handleDoubleTap(details);
}
// need set _lastTapDownPosition, otherwise it would be last single tap position
void _handleLongPress() {
D.assert(!this.ignorePointer);
this.handleLongPress();
}
void selectPosition(SelectionChangedCause? cause = null) {
D.assert(cause != null);
this._layoutText(this.constraints.maxWidth);
D.assert(this._lastTapDownPosition != null);
if (this.onSelectionChanged != null) {
TextPosition position = this._textPainter.getPositionForOffset(this.globalToLocal(this._lastTapDownPosition));
this.onSelectionChanged(TextSelection.fromPosition(position), this, cause.Value);
}
}
void selectWord(SelectionChangedCause? cause = null) {
this._layoutText(this.constraints.maxWidth);
D.assert(this._lastTapDownPosition != null);

}
}
void selectWordEdge(SelectionChangedCause cause) {
this._layoutText(this.constraints.maxWidth);
D.assert(this._lastTapDownPosition != null);
if (this.onSelectionChanged != null) {
TextPosition position = this._textPainter.getPositionForOffset(this.globalToLocal(this._lastTapDownPosition));
TextRange word = this._textPainter.getWordBoundary(position);
if (position.offset - word.start <= 1) {
this.onSelectionChanged(
TextSelection.collapsed(offset: word.start, affinity: TextAffinity.downstream),
this,
cause
);
} else {
this.onSelectionChanged(
TextSelection.collapsed(offset: word.end, affinity: TextAffinity.upstream),
this,
cause
);
}
}
}
TextSelection _selectWordAtOffset(TextPosition position) {
D.assert(this._textLayoutLastWidth == this.constraints.maxWidth);
var word = this._textPainter.getWordBoundary(position);
if (position.offset >= word.end) {
return TextSelection.fromPosition(position);
}
return new TextSelection(baseOffset: word.start, extentOffset: word.end);
}
void _layoutText(float constraintWidth) {
if (this._textLayoutLastWidth == constraintWidth) {
return;
}
var caretMargin = _kCaretGap + _kCaretWidth;
var avialableWidth = Mathf.Max(0.0f, constraintWidth - caretMargin);
var maxWidth = this._isMultiline ? avialableWidth : float.PositiveInfinity;
this._textPainter.layout(minWidth: avialableWidth, maxWidth: maxWidth);
this._textLayoutLastWidth = constraintWidth;
}
protected override void performLayout() {
this._layoutText(this.constraints.maxWidth);
this._caretPrototype = Rect.fromLTWH(0.0f, _kCaretHeightOffset, _kCaretWidth,

return true;
}
protected void markNeedsTextLayout() {
this._textLayoutLastWidth = null;
this.markNeedsLayout();
}
var caretRec = this._caretPrototype.shift(caretOffset + effectiveOffset);
canvas.drawRect(caretRec, paint);
if (!caretRec.Equals(this._lastCaretRect)) {
this._lastCaretRect = caretRec;
var caretRect = this._caretPrototype.shift(caretOffset + effectiveOffset);
if (this.cursorRadius == null) {
canvas.drawRect(caretRect, paint);
}
else {
RRect caretRRect = RRect.fromRectAndRadius(caretRect, this.cursorRadius);
canvas.drawRRect(caretRRect, paint);
}
if (!caretRect.Equals(this._lastCaretRect)) {
this._lastCaretRect = caretRect;
this.onCaretChanged(caretRec);
this.onCaretChanged(caretRect);
}
}
}

this._textPainter.paint(context.canvas, effectiveOffset);
}
void _handleSetSelection(TextSelection selection) {
this.onSelectionChanged(selection, this, SelectionChangedCause.keyboard);
}
void _handleTapDown(TapDownDetails details) {
D.assert(!this.ignorePointer);
this.handleTapDown(details);
}
void _handleTap() {
D.assert(!this.ignorePointer);
this.handleTap();
}
void _handleDoubleTap(DoubleTapDetails details) {
D.assert(!this.ignorePointer);
this.handleDoubleTap(details);
}
void _handleLongPress() {
D.assert(!this.ignorePointer);
this.handleLongPress();
}
void markNeedsSemanticsUpdate() {
// todo
}

return Mathf.Max(this.preferredLineHeight, this._textPainter.height);
}
void _layoutText(float constraintWidth) {
if (this._textLayoutLastWidth == constraintWidth) {
return;
}
var caretMargin = _kCaretGap + _kCaretWidth;
var avialableWidth = Mathf.Max(0.0f, constraintWidth - caretMargin);
var maxWidth = this._isMultiline ? avialableWidth : float.PositiveInfinity;
this._textPainter.layout(minWidth: avialableWidth, maxWidth: maxWidth);
this._textLayoutLastWidth = constraintWidth;
}
TextSelection _selectWordAtOffset(TextPosition position) {
D.assert(this._textLayoutLastWidth == this.constraints.maxWidth);
var word = this._textPainter.getWordBoundary(position);
if (position.offset >= word.end) {
return TextSelection.fromPosition(position);
}
return new TextSelection(baseOffset: word.start, extentOffset: word.end);
}
void _selectForTap(Offset pointerPosition) {
if (this.onSelectionChanged != null) {
var position = this._textPainter.getPositionForOffset(this.globalToLocal(pointerPosition));
this.onSelectionChanged(TextSelection.fromPosition(position), this, SelectionChangedCause.tap);
}
}
bool _isMultiline {
get { return this._maxLines != 1; }
}

return 0.0f;
}
public override Rect describeApproximatePaintClip(RenderObject child) {
return this._hasVisualOverflow ? Offset.zero & size : null;
}
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) {
base.debugFillProperties(properties);
properties.add(new DiagnosticsProperty<Color>("cursorColor", this.cursorColor));

26
Runtime/service/keyboard.cs


namespace Unity.UIWidgets.service {
interface KeyboardDelegate: IDisposable {
void show();
void hide();

if (currentEvent != null && currentEvent.type == EventType.KeyDown) {
var action = TextInputUtils.getInputAction(currentEvent);
if (action != null) {
Window.instance.run(() => { TextInput._performAction(this._client, action.Value); });
if (currentEvent.keyCode == KeyCode.Return) {
Window.instance.run(() => { TextInput._performAction(this._client, TextInputAction.newline); });
if (action == null || action == TextInputAction.newline) {
if (currentEvent.keyCode == KeyCode.None) {
char ch = currentEvent.character;
if (ch == '\r' || ch == 3) {
ch = '\n';
}
this._value = this._value.clearCompose();
if (_validateCharacter(ch)) {
this._value = this._value.insert(new string(ch, 1));
}
Window.instance.run(() => { TextInput._updateEditingState(this._client, this._value); });
if (currentEvent.character != '\0') {
char ch = currentEvent.character;
if (ch == '\r' || ch == 3) {
ch = '\n';
this._value = this._value.clearCompose();
if (_validateCharacter(ch)) {
this._value = this._value.insert(new string(ch, 1));
}
Window.instance.run(() => { TextInput._updateEditingState(this._client, this._value); });
}
currentEvent.Use();

52
Runtime/service/text_input.cs


join,
route,
emergencyCall,
newline,
moveLeft,
moveRight,
moveUp,
moveDown,
moveLineStart,
moveLineEnd,
moveTextStart,
moveTextEnd,
movePageUp,
movePageDown,
moveGraphicalLineStart,
moveGraphicalLineEnd,
moveWordLeft,
moveWordRight,
moveParagraphForward,
moveParagraphBackward,
moveToStartOfNextWord,
moveToEndOfPreviousWord,
selectLeft,
selectRight,
selectUp,
selectDown,
selectTextStart,
selectTextEnd,
selectPageUp,
selectPageDown,
expandSelectGraphicalLineStart,
expandSelectGraphicalLineEnd,
selectGraphicalLineStart,
selectGraphicalLineEnd,
selectWordLeft,
selectWordRight,
selectToEndOfPreviousWord,
selectToStartOfNextWord,
selectParagraphBackward,
selectParagraphForward,
delete,
backspace,
deleteWordBack,
deleteWordForward,
deleteLineBack,
cut,
copy,
paste,
selectAll,
selectNone,
scrollStart,
scrollEnd,
scrollPageUp,
scrollPageDown,
newline
}
public enum TextCapitalization {

228
Runtime/widgets/editable_text.cs


using System;
using System.Collections.Generic;
using RSG;
using Unity.UIWidgets.animation;
using Unity.UIWidgets.async;
using Unity.UIWidgets.foundation;

}
}
public class EditableTextState : AutomaticKeepAliveClientMixin<EditableText>, TextInputClient,
public class EditableTextState : AutomaticKeepAliveClientMixin<EditableText>, WidgetsBindingObserver, TextInputClient,
TextSelectionDelegate {
const int _kObscureShowLatestCharCursorTicks = 3;
static TimeSpan _kCursorBlinkHalfPeriod = TimeSpan.FromMilliseconds(500);

TextSelectionOverlay _selectionOverlay;
int _obscureShowCharTicksPending = 0;
int _obscureLatestCharIndex;
bool _textChangedSinceLastCaretUpdate = false;
protected override bool wantKeepAlive {
get { return this.widget.focusNode.hasFocus; }

this._formatAndSetValue(value);
}
public TextEditingValue getValueForAction(TextInputAction operation) {
TextPosition newPosition = null;
TextPosition newExtend = null;
TextEditingValue newValue = null;
TextSelection newSelection = null;
TextPosition startPos = new TextPosition(this._value.selection.start, this._value.selection.affinity);
switch (operation) {
case TextInputAction.moveLeft:
newValue = this._value.moveLeft();
break;
case TextInputAction.moveRight:
newValue = this._value.moveRight();
break;
case TextInputAction.moveUp:
newPosition = this.renderEditable.getPositionUp(startPos);
break;
case TextInputAction.moveDown:
newPosition = this.renderEditable.getPositionDown(startPos);
break;
case TextInputAction.moveLineStart:
newPosition = this.renderEditable.getParagraphStart(startPos, TextAffinity.downstream);
break;
case TextInputAction.moveLineEnd:
newPosition = this.renderEditable.getParagraphEnd(startPos, TextAffinity.upstream);
break;
case TextInputAction.moveWordRight:
newPosition = this.renderEditable.getWordRight(startPos);
break;
case TextInputAction.moveWordLeft:
newPosition = this.renderEditable.getWordLeft(startPos);
break;
// case TextInputAction.MoveToStartOfNextWord: MoveToStartOfNextWord(); break;
// case TextInputAction.MoveToEndOfPreviousWord: MoveToEndOfPreviousWord(); break;
case TextInputAction.moveTextStart:
newPosition = new TextPosition(0);
break;
case TextInputAction.moveTextEnd:
newPosition = new TextPosition(this._value.text.Length);
break;
case TextInputAction.moveParagraphForward:
newPosition = this.renderEditable.getParagraphForward(startPos);
break;
case TextInputAction.moveParagraphBackward:
newPosition = this.renderEditable.getParagraphBackward(startPos);
break;
case TextInputAction.moveGraphicalLineStart:
newPosition = this.renderEditable.getLineStartPosition(startPos, TextAffinity.downstream);
break;
case TextInputAction.moveGraphicalLineEnd:
newPosition = this.renderEditable.getLineEndPosition(startPos, TextAffinity.upstream);
break;
case TextInputAction.selectLeft:
newValue = this._value.extendLeft();
break;
case TextInputAction.selectRight:
newValue = this._value.extendRight();
break;
case TextInputAction.selectUp:
newExtend = this.renderEditable.getPositionUp(this._value.selection.extendPos);
break;
case TextInputAction.selectDown:
newExtend = this.renderEditable.getPositionDown(this._value.selection.extendPos);
break;
case TextInputAction.selectWordRight:
newExtend = this.renderEditable.getWordRight(this._value.selection.extendPos);
break;
case TextInputAction.selectWordLeft:
newExtend = this.renderEditable.getWordLeft(this._value.selection.extendPos);
break;
// case TextInputAction.SelectToEndOfPreviousWord: SelectToEndOfPreviousWord(); break;
// case TextInputAction.SelectToStartOfNextWord: SelectToStartOfNextWord(); break;
//
case TextInputAction.selectTextStart:
newExtend = new TextPosition(0);
break;
case TextInputAction.selectTextEnd:
newExtend = new TextPosition(this._value.text.Length);
break;
case TextInputAction.expandSelectGraphicalLineStart:
if (this._value.selection.isCollapsed ||
!this.renderEditable.isLineEndOrStart(this._value.selection.start)) {
newSelection = new TextSelection(this.renderEditable.getLineStartPosition(startPos).offset,
this._value.selection.end, this._value.selection.affinity);
}
break;
case TextInputAction.expandSelectGraphicalLineEnd:
if (this._value.selection.isCollapsed ||
!this.renderEditable.isLineEndOrStart(this._value.selection.end)) {
newSelection = new TextSelection(this._value.selection.start,
this.renderEditable.getLineEndPosition(this._value.selection.endPos).offset,
this._value.selection.affinity);
}
break;
case TextInputAction.selectParagraphForward:
newExtend = this.renderEditable.getParagraphForward(this._value.selection.extendPos);
break;
case TextInputAction.selectParagraphBackward:
newExtend = this.renderEditable.getParagraphBackward(this._value.selection.extendPos);
break;
case TextInputAction.selectGraphicalLineStart:
newExtend = this.renderEditable.getLineStartPosition(this._value.selection.extendPos);
break;
case TextInputAction.selectGraphicalLineEnd:
newExtend = this.renderEditable.getLineEndPosition(startPos);
break;
case TextInputAction.delete:
newValue = this._value.deleteSelection(false);
break;
case TextInputAction.backspace:
newValue = this._value.deleteSelection();
break;
case TextInputAction.selectAll:
newSelection = this._value.selection.copyWith(baseOffset: 0, extentOffset: this._value.text.Length);
break;
}
if (newPosition != null) {
return this._value.copyWith(selection: TextSelection.fromPosition(newPosition));
}
else if (newExtend != null) {
return this._value.copyWith(selection: this._value.selection.copyWith(extentOffset: newExtend.offset));
}
else if (newSelection != null) {
return this._value.copyWith(selection: newSelection);
}
else if (newValue != null) {
return newValue;
}
return this._value;
}
TextEditingValue newValue;
switch (action) {
case TextInputAction.newline:
if (this.widget.maxLines == 1) {

case TextInputAction.search:
this._finalizeEditing(true);
break;
case TextInputAction.next:
case TextInputAction.previous:
case TextInputAction.continueAction:
case TextInputAction.join:
case TextInputAction.route:
case TextInputAction.emergencyCall:
default:
break;
default:
newValue = this.getValueForAction(action);
if (newValue != this.textEditingValue) {
this.textEditingValue = newValue;
}
break;
}
}

this._textInputConnection.setEditingState(localValue);
}
TextEditingValue _value {
get { return this.widget.controller.value; }
set { this.widget.controller.value = value; }
}
bool _hasFocus {
get { return this.widget.focusNode.hasFocus; }
}
bool _isMultiline {
get { return this.widget.maxLines != 1; }
}
// Calculate the new scroll offset so the cursor remains visible.
float _getScrollOffsetForCaret(Rect caretRect) {

}
}
bool _textChangedSinceLastCaretUpdate = false;
Rect _currentCaretRect;
void _handleCaretChanged(Rect caretRect) {

);
});
}
double _lastBottomViewInset;
public void didChangeMetrics() {
if (this._lastBottomViewInset < Window.instance.viewInsets.bottom) {
this._showCaretOnScreen();
}
this._lastBottomViewInset = Window.instance.viewInsets.bottom;
}
public void didChangeTextScaleFactor() {}
public void didChangeLocales(List<Locale> locale) {}
public IPromise<bool> didPopRoute() {
return Promise<bool>.Resolved(false);
}
public IPromise<bool> didPushRoute(string route) {
return Promise<bool>.Resolved(false);
}
void _formatAndSetValue(TextEditingValue value) {
var textChanged = (this._value == null ? null : this._value.text) != (value == null ? null : value.text);

}
}
TextEditingValue _value {
get { return this.widget.controller.value; }
set { this.widget.controller.value = value; }
}
bool _hasFocus {
get { return this.widget.focusNode.hasFocus; }
}
bool _isMultiline {
get { return this.widget.maxLines != 1; }
}
void _didChangeTextEditingValue() {
this._updateRemoteEditingValueIfNeeded();

this._openOrCloseInputConnectionIfNeeded();
this._startOrStopCursorTimerIfNeeded();
this._updateOrDisposeSelectionOverlayIfNeeded();
if (!this._hasFocus) {
this._value = new TextEditingValue(text: this._value.text);
if (this._hasFocus) {
WidgetsBinding.instance.addObserver(this);
this._lastBottomViewInset = Window.instance.viewInsets.bottom;
this._showCaretOnScreen();
if (!this._value.selection.isValid) {
this.widget.controller.selection = TextSelection.collapsed(offset: this._value.text.Length);
}
else if (!this._value.selection.isValid) {
this.widget.controller.selection = TextSelection.collapsed(offset: this._value.text.Length);
else {
WidgetsBinding.instance.removeObserver(this);
this._value = new TextEditingValue(text: this._value.text);
this.updateKeepAlive();
}

offset: offset,
onSelectionChanged: this._handleSelectionChanged,
onCaretChanged: this._handleCaretChanged,
rendererIgnoresPointer: this.widget.rendererIgnoresPointer
rendererIgnoresPointer: this.widget.rendererIgnoresPointer,
textSelectionDelegate: this
)
)
);

public readonly SelectionChangedHandler onSelectionChanged;
public readonly CaretChangedHandler onCaretChanged;
public readonly bool rendererIgnoresPointer;
public readonly TextSelectionDelegate textSelectionDelegate;
public _Editable(TextSpan textSpan = null, TextEditingValue value = null,

bool autocorrect = false, ViewportOffset offset = null, SelectionChangedHandler onSelectionChanged = null,
CaretChangedHandler onCaretChanged = null, bool rendererIgnoresPointer = false,
Key key = null) : base(key) {
Key key = null, TextSelectionDelegate textSelectionDelegate = null) : base(key) {
this.textSpan = textSpan;
this.value = value;
this.cursorColor = cursorColor;

this.onSelectionChanged = onSelectionChanged;
this.onCaretChanged = onCaretChanged;
this.rendererIgnoresPointer = rendererIgnoresPointer;
this.textSelectionDelegate = textSelectionDelegate;
}
public override RenderObject createRenderObject(BuildContext context) {

obscureText: this.obscureText,
onSelectionChanged: this.onSelectionChanged,
onCaretChanged: this.onCaretChanged,
ignorePointer: this.rendererIgnoresPointer
ignorePointer: this.rendererIgnoresPointer,
textSelectionDelegate: this.textSelectionDelegate
);
}

edit.onCaretChanged = this.onCaretChanged;
edit.ignorePointer = this.rendererIgnoresPointer;
edit.obscureText = this.obscureText;
edit.textSelectionDelegate = this.textSelectionDelegate;
}
}
}

82
Runtime/service/raw_keyboard.cs


using System.Collections.Generic;
using Unity.UIWidgets.foundation;
using UnityEngine;
namespace Unity.UIWidgets.service {
public class RawKeyboard {
public static readonly RawKeyboard instance = new RawKeyboard();
RawKeyboard() {
}
readonly List<ValueChanged<RawKeyEvent>> _listeners = new List<ValueChanged<RawKeyEvent>>();
public void addListener(ValueChanged<RawKeyEvent> listener) {
this._listeners.Add(listener);
}
public void removeListener(ValueChanged<RawKeyEvent> listener) {
this._listeners.Remove(listener);
}
internal void _handleKeyEvent(Event evt) {
if (this._listeners.isEmpty()) {
return;
}
var keyboardEvent = RawKeyEvent.fromEvent(evt);
if (keyboardEvent == null) {
return;
}
foreach (var listener in new List<ValueChanged<RawKeyEvent>>(this._listeners)) {
if (this._listeners.Contains(listener)) {
listener(keyboardEvent);
}
}
}
}
public abstract class RawKeyEvent {
protected RawKeyEvent(RawKeyEventData data) {
this.data = data;
}
public static RawKeyEvent fromEvent(Event evt) {
if (evt == null) {
return null;
}
if (evt.type == EventType.KeyDown) {
return new RawKeyDownEvent(new RawKeyEventData(evt));
} else if (evt.type == EventType.KeyUp) {
return new RawKeyUpEvent(new RawKeyEventData(evt));
}
return null;
}
public readonly RawKeyEventData data;
}
public class RawKeyDownEvent: RawKeyEvent {
public RawKeyDownEvent(RawKeyEventData data) : base(data) {
}
}
public class RawKeyUpEvent : RawKeyEvent {
public RawKeyUpEvent(RawKeyEventData data) : base(data) {
}
}
public class RawKeyEventData {
public readonly Event unityEvent;
public RawKeyEventData(Event unityEvent) {
this.unityEvent = unityEvent;
}
}
}

11
Runtime/service/text_input_utils.cs.meta


fileFormatVersion: 2
guid: 2288dc63570aa4d8db1bd6673b12634f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

153
Runtime/service/text_input_utils.cs


using System.Collections.Generic;
using UnityEngine;
namespace Unity.UIWidgets.service {
static partial class TextInputUtils {
static Dictionary<Event, TextInputAction> _keyToOperations;
public static TextInputAction? getInputAction(Event evt) {
if (_keyToOperations == null) {
initKeyToOperations();
}
EventModifiers m = evt.modifiers;
evt.modifiers &= ~EventModifiers.CapsLock;
TextInputAction result;
var exists = _keyToOperations.TryGetValue(evt, out result);
evt.modifiers = m;
if (exists) {
return result;
}
return null;
}
public static void initKeyToOperations() {
if (_keyToOperations != null) {
return;
}
_keyToOperations = new Dictionary<Event, TextInputAction>();
// key mappings shared by the platforms
mapKey("return", TextInputAction.newline);
mapKey("left", TextInputAction.moveLeft);
mapKey("right", TextInputAction.moveRight);
mapKey("up", TextInputAction.moveUp);
mapKey("down", TextInputAction.moveDown);
mapKey("#left", TextInputAction.selectLeft);
mapKey("#right", TextInputAction.selectRight);
mapKey("#up", TextInputAction.selectUp);
mapKey("#down", TextInputAction.selectDown);
mapKey("delete", TextInputAction.delete);
mapKey("backspace", TextInputAction.backspace);
mapKey("#backspace", TextInputAction.backspace);
// OSX is the special case for input shortcuts
if (SystemInfo.operatingSystemFamily == OperatingSystemFamily.MacOSX) {
// Keyboard mappings for mac
// TODO mapKey ("home", TextInputAction.scrollStart);
// TODO mapKey ("end", TextInputAction.scrollEnd);
// TODO mapKey ("page up", TextInputAction.scrollPageUp);
// TODO mapKey ("page down", TextInputAction.scrollPageDown);
mapKey("^left", TextInputAction.moveGraphicalLineStart);
mapKey("^right", TextInputAction.moveGraphicalLineEnd);
// TODO mapKey ("^up", TextInputAction.scrollPageUp);
// TODO mapKey ("^down", TextInputAction.scrollPageDown);
mapKey("&left", TextInputAction.moveWordLeft);
mapKey("&right", TextInputAction.moveWordRight);
mapKey("&up", TextInputAction.moveParagraphBackward);
mapKey("&down", TextInputAction.moveParagraphForward);
mapKey("%left", TextInputAction.moveGraphicalLineStart);
mapKey("%right", TextInputAction.moveGraphicalLineEnd);
mapKey("%up", TextInputAction.moveTextStart);
mapKey("%down", TextInputAction.moveTextEnd);
mapKey("#home", TextInputAction.selectTextStart);
mapKey("#end", TextInputAction.selectTextEnd);
// TODO mapKey ("#page up", TextInputAction.selectPageUp);
// TODO mapKey ("#page down", TextInputAction.selectPageDown);
mapKey("#^left", TextInputAction.expandSelectGraphicalLineStart);
mapKey("#^right", TextInputAction.expandSelectGraphicalLineEnd);
mapKey("#^up", TextInputAction.selectParagraphBackward);
mapKey("#^down", TextInputAction.selectParagraphForward);
mapKey("#&left", TextInputAction.selectWordLeft);
mapKey("#&right", TextInputAction.selectWordRight);
mapKey("#&up", TextInputAction.selectParagraphBackward);
mapKey("#&down", TextInputAction.selectParagraphForward);
mapKey("#%left", TextInputAction.expandSelectGraphicalLineStart);
mapKey("#%right", TextInputAction.expandSelectGraphicalLineEnd);
mapKey("#%up", TextInputAction.selectTextStart);
mapKey("#%down", TextInputAction.selectTextEnd);
mapKey("%a", TextInputAction.selectAll);
mapKey("%x", TextInputAction.cut);
mapKey("%c", TextInputAction.copy);
mapKey("%v", TextInputAction.paste);
// emacs-like keybindings
mapKey("^d", TextInputAction.delete);
mapKey("^h", TextInputAction.backspace);
mapKey("^b", TextInputAction.moveLeft);
mapKey("^f", TextInputAction.moveRight);
mapKey("^a", TextInputAction.moveLineStart);
mapKey("^e", TextInputAction.moveLineEnd);
mapKey("&delete", TextInputAction.deleteWordForward);
mapKey("&backspace", TextInputAction.deleteWordBack);
mapKey("%backspace", TextInputAction.deleteLineBack);
}
else {
// Windows/Linux keymappings
mapKey("home", TextInputAction.moveGraphicalLineStart);
mapKey("end", TextInputAction.moveGraphicalLineEnd);
// TODO mapKey ("page up", TextInputAction.movePageUp);
// TODO mapKey ("page down", TextInputAction.movePageDown);
mapKey("%left", TextInputAction.moveWordLeft);
mapKey("%right", TextInputAction.moveWordRight);
mapKey("%up", TextInputAction.moveParagraphBackward);
mapKey("%down", TextInputAction.moveParagraphForward);
mapKey("^left", TextInputAction.moveToEndOfPreviousWord);
mapKey("^right", TextInputAction.moveToStartOfNextWord);
mapKey("^up", TextInputAction.moveParagraphBackward);
mapKey("^down", TextInputAction.moveParagraphForward);
mapKey("#^left", TextInputAction.selectToEndOfPreviousWord);
mapKey("#^right", TextInputAction.selectToStartOfNextWord);
mapKey("#^up", TextInputAction.selectParagraphBackward);
mapKey("#^down", TextInputAction.selectParagraphForward);
mapKey("#home", TextInputAction.selectGraphicalLineStart);
mapKey("#end", TextInputAction.selectGraphicalLineEnd);
// TODO mapKey ("#page up", TextInputAction.selectPageUp);
// TODO mapKey ("#page down", TextInputAction.selectPageDown);
mapKey("^delete", TextInputAction.deleteWordForward);
mapKey("^backspace", TextInputAction.deleteWordBack);
mapKey("%backspace", TextInputAction.deleteLineBack);
mapKey("^a", TextInputAction.selectAll);
mapKey("^x", TextInputAction.cut);
mapKey("^c", TextInputAction.copy);
mapKey("^v", TextInputAction.paste);
mapKey("#delete", TextInputAction.cut);
mapKey("^insert", TextInputAction.copy);
mapKey("#insert", TextInputAction.paste);
}
}
static void mapKey(string key, TextInputAction action) {
_keyToOperations[Event.KeyboardEvent(key)] = action;
}
}
}
正在加载...
取消
保存