Skip to content

Commit

Permalink
fix(textbox): added SelectionBeforeKeyDown to the Skia TextBox hierarchy
Browse files Browse the repository at this point in the history
This deals with idiosyncrasies of native behaviour on different Skia targets.
  • Loading branch information
ramezgerges committed Jul 3, 2023
1 parent 4665dc6 commit 0228293
Show file tree
Hide file tree
Showing 10 changed files with 60 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@
<ColumnDefinition Width="350"/>
<ColumnDefinition Width="350"/>
</Grid.ColumnDefinitions>
<TextBox Grid.Column="0" Grid.Row="0" Text="Lorem"/>
<PasswordBox Grid.Column="0" Grid.Row="0" Password="Lorem"/>
<TextBox Grid.Column="1" Grid.Row="0" Text="ipsum"/>
<TextBox Grid.Column="2" Grid.Row="0" Text="dolor"/>
<TextBox Grid.Column="0" Grid.Row="1" Text="sit"/>
<TextBox Grid.Column="1" Grid.Row="1" Text="amet"/>
<PasswordBox Grid.Column="1" Grid.Row="1" Password="amet"/>
<TextBox Grid.Column="2" Grid.Row="1" Text="consectetur"/>
<Button Grid.Column="0" Grid.Row="2" Width="80" Height="30" Content="Clear" Click="Button_OnClick"/>
<Button Grid.Column="1" Grid.Row="2" Width="80" Height="30" Content="Clear" Click="Button_OnClick"/>
Expand Down
3 changes: 3 additions & 0 deletions src/Uno.UI.Runtime.Skia.Gtk/UI/Controls/GtkTextBoxView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ public void RemoveFromTextInputLayer()

public abstract (int start, int length) Selection { get; set; }

// On Gtk, KeyDown is fired before Selection is updated, so nothing special needs to be done.
public (int start, int length) SelectionBeforeKeyDown => Selection;

public abstract bool IsCompatible(TextBox textBox);

public abstract IDisposable ObserveTextChanges(EventHandler onChanged);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

using System;
using System.Windows;
using System.Windows.Input;
using Uno.Disposables;
using Uno.UI.Runtime.Skia.Wpf.UI.Controls;
using WpfElement = System.Windows.UIElement;
Expand All @@ -18,6 +19,7 @@ internal class PasswordTextBoxView : WpfTextBoxView
private readonly WpfGrid _grid = new();
private readonly SerialDisposable _visibleControlTextChangedSubscription = new();
private EventHandler? _textChangedWatcher;
private (int start, int length) _selectionBeforeKeyDown;

public PasswordTextBoxView()
{
Expand All @@ -28,6 +30,9 @@ public PasswordTextBoxView()
_passwordBox.Visibility = Visibility.Collapsed;
_grid.Children.Add(_passwordBox);
_grid.Children.Add(_textBox);

_textBox.PreviewKeyDown += OnPreviewKeyDown;
_passwordBox.PreviewKeyDown += OnPreviewKeyDown;
}

public override string Text
Expand All @@ -47,6 +52,12 @@ public override (int start, int length) Selection
get => (_textBox.SelectionStart, _textBox.SelectionLength);
set => (_textBox.SelectionStart, _textBox.SelectionLength) = value;
}

public override (int start, int length) SelectionBeforeKeyDown
{
get => (_selectionBeforeKeyDown.start, _selectionBeforeKeyDown.length);
protected set => (_selectionBeforeKeyDown.start, _selectionBeforeKeyDown.length) = value;
}

public override bool IsCompatible(Windows.UI.Xaml.Controls.TextBox textBox) => textBox is Windows.UI.Xaml.Controls.PasswordBox;

Expand Down Expand Up @@ -118,4 +129,10 @@ private void ObserveVisibleControlTextChanges()
private void OnCommonTextChanged() => _textChangedWatcher?.Invoke(this, EventArgs.Empty);

private WpfElement GetDisplayedElement() => _textBox.Visibility == Visibility.Visible ? _textBox : _passwordBox;

private void OnPreviewKeyDown(object sender, KeyEventArgs e)
{
// On WPF, KeyDown is fired AFTER Selection is already changed to the new value
SelectionBeforeKeyDown = Selection;
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using Uno.Disposables;
using Uno.UI.Runtime.Skia.Wpf.UI.Controls;
using Windows.UI.Xaml.Controls;
Expand All @@ -14,9 +15,11 @@ namespace Uno.UI.Runtime.Skia.Wpf.Extensions.UI.Xaml.Controls;
internal class TextTextBoxView : WpfTextBoxView
{
private readonly WpfTextViewTextBox _textBox = new();
private (int start, int length) _selectionBeforeKeyDown;

public TextTextBoxView()
{
_textBox.PreviewKeyDown += OnPreviewKeyDown;
}

public override string Text
Expand All @@ -33,6 +36,12 @@ public override (int start, int length) Selection
set => (_textBox.SelectionStart, _textBox.SelectionLength) = value;
}

public override (int start, int length) SelectionBeforeKeyDown
{
get => (_selectionBeforeKeyDown.start, _selectionBeforeKeyDown.length);
protected set => (_selectionBeforeKeyDown.start, _selectionBeforeKeyDown.length) = value;
}

public override void SetFocus() => _textBox.Focus();

public override bool IsCompatible(Windows.UI.Xaml.Controls.TextBox textBox) => textBox is not PasswordBox;
Expand All @@ -49,4 +58,10 @@ public override void UpdateProperties(Windows.UI.Xaml.Controls.TextBox winUIText
SetControlProperties(_textBox, winUITextBox);
SetTextBoxProperties(_textBox, winUITextBox);
}

private void OnPreviewKeyDown(object sender, KeyEventArgs e)
{
// On WPF, KeyDown is fired AFTER Selection is already changed to the new value
SelectionBeforeKeyDown = Selection;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ protected WpfTextBoxView()
public bool IsDisplayed => RootElement.Parent is not null;

public abstract (int start, int length) Selection { get; set; }

public abstract (int start, int length) SelectionBeforeKeyDown { get; protected set; }

/// <summary>
/// Represents the root element of the input layout.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ internal interface IOverlayTextBoxView

(int start, int length) Selection { get; set; }

/// <summary>
/// On some platforms (namely Skia.WPF) KeyDown is fired after Selection is already set to the new value.
/// This property is provided to allow access to the selection value right before KeyDown.
/// </summary>
(int start, int length) SelectionBeforeKeyDown { get; }

/// <summary>
/// Returns a value indicating whether this TextBoxView is compatible with the given TextBox state.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ internal interface IOverlayTextBoxViewExtension
int GetSelectionStart();

int GetSelectionLength();

int GetSelectionStartBeforeKeyDown();

int GetSelectionLengthBeforeKeyDown();

void UpdateProperties();
}
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,11 @@ public int GetSelectionLength()
_selectionLengthCache ?? 0 :
_textBoxView?.Selection.length ?? 0;
}

public int GetSelectionStartBeforeKeyDown() => _textBoxView!.SelectionBeforeKeyDown.start;

public int GetSelectionLengthBeforeKeyDown() => _textBoxView!.SelectionBeforeKeyDown.length;

private void EnsureTextBoxView(TextBox textBox)
{
if (_textBoxView is null ||
Expand Down
6 changes: 3 additions & 3 deletions src/Uno.UI/UI/Xaml/Controls/TextBox/TextBox.cs
Original file line number Diff line number Diff line change
Expand Up @@ -971,7 +971,7 @@ protected override void OnKeyDown(KeyRoutedEventArgs args)
}
break;
case VirtualKey.Down:
if (SelectionStart != Text.Length)
if (TextBoxView.SelectionBeforeKeyDown.start != Text.Length)
{
SelectionStart = Text.Length;
args.Handled = true;
Expand All @@ -982,13 +982,13 @@ protected override void OnKeyDown(KeyRoutedEventArgs args)
}
break;
case VirtualKey.Left:
if (SelectionStart != 0)
if (TextBoxView.SelectionBeforeKeyDown.start != 0)
{
args.Handled = true;
}
break;
case VirtualKey.Right:
if (SelectionStart != Text.Length)
if (TextBoxView.SelectionBeforeKeyDown.start != Text.Length)
{
args.Handled = true;
}
Expand Down
3 changes: 3 additions & 0 deletions src/Uno.UI/UI/Xaml/Controls/TextBox/TextBoxView.skia.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ public TextBoxView(TextBox textBox)
}
}

public (int start, int length) SelectionBeforeKeyDown =>
(_textBoxExtension!.GetSelectionStartBeforeKeyDown(), _textBoxExtension.GetSelectionLengthBeforeKeyDown());

internal IOverlayTextBoxViewExtension? Extension => _textBoxExtension;

public TextBox? TextBox
Expand Down

0 comments on commit 0228293

Please sign in to comment.