committed by
GitHub
57 changed files with 757 additions and 285 deletions
@ -0,0 +1,5 @@ |
|||
<ProjectConfiguration> |
|||
<Settings> |
|||
<IgnoreThisComponentCompletely>True</IgnoreThisComponentCompletely> |
|||
</Settings> |
|||
</ProjectConfiguration> |
|||
@ -0,0 +1,5 @@ |
|||
<ProjectConfiguration> |
|||
<Settings> |
|||
<IgnoreThisComponentCompletely>True</IgnoreThisComponentCompletely> |
|||
</Settings> |
|||
</ProjectConfiguration> |
|||
@ -1,7 +1,3 @@ |
|||
<ProjectConfiguration> |
|||
<Settings> |
|||
<AdditionalFilesToIncludeForProject> |
|||
<Value>..\..\tools\MicroComGenerator\bin\Debug\net6.0\**.*</Value> |
|||
</AdditionalFilesToIncludeForProject> |
|||
</Settings> |
|||
<Settings /> |
|||
</ProjectConfiguration> |
|||
@ -1,7 +1,3 @@ |
|||
<ProjectConfiguration> |
|||
<Settings> |
|||
<AdditionalFilesToIncludeForProject> |
|||
<Value>..\..\tools\MicroComGenerator\bin\Debug\net6.0\**.*</Value> |
|||
</AdditionalFilesToIncludeForProject> |
|||
</Settings> |
|||
<Settings /> |
|||
</ProjectConfiguration> |
|||
@ -0,0 +1,5 @@ |
|||
<ProjectConfiguration> |
|||
<Settings> |
|||
<IgnoreThisComponentCompletely>True</IgnoreThisComponentCompletely> |
|||
</Settings> |
|||
</ProjectConfiguration> |
|||
@ -0,0 +1,5 @@ |
|||
<ProjectConfiguration> |
|||
<Settings> |
|||
<IgnoreThisComponentCompletely>True</IgnoreThisComponentCompletely> |
|||
</Settings> |
|||
</ProjectConfiguration> |
|||
@ -0,0 +1,5 @@ |
|||
<ProjectConfiguration> |
|||
<Settings> |
|||
<IgnoreThisComponentCompletely>True</IgnoreThisComponentCompletely> |
|||
</Settings> |
|||
</ProjectConfiguration> |
|||
@ -0,0 +1,5 @@ |
|||
<ProjectConfiguration> |
|||
<Settings> |
|||
<IgnoreThisComponentCompletely>True</IgnoreThisComponentCompletely> |
|||
</Settings> |
|||
</ProjectConfiguration> |
|||
@ -0,0 +1,5 @@ |
|||
<ProjectConfiguration> |
|||
<Settings> |
|||
<IgnoreThisComponentCompletely>True</IgnoreThisComponentCompletely> |
|||
</Settings> |
|||
</ProjectConfiguration> |
|||
@ -0,0 +1,5 @@ |
|||
<ProjectConfiguration> |
|||
<Settings> |
|||
<IgnoreThisComponentCompletely>True</IgnoreThisComponentCompletely> |
|||
</Settings> |
|||
</ProjectConfiguration> |
|||
@ -0,0 +1,5 @@ |
|||
<ProjectConfiguration> |
|||
<Settings> |
|||
<IgnoreThisComponentCompletely>True</IgnoreThisComponentCompletely> |
|||
</Settings> |
|||
</ProjectConfiguration> |
|||
@ -0,0 +1,30 @@ |
|||
using System; |
|||
using Avalonia.Input; |
|||
|
|||
namespace Avalonia.Platform |
|||
{ |
|||
/// <summary>
|
|||
/// A default implementation of <see cref="IPlatformSettings"/> for platforms which don't have
|
|||
/// an OS-specific implementation.
|
|||
/// </summary>
|
|||
public class DefaultPlatformSettings : IPlatformSettings |
|||
{ |
|||
public Size GetTapSize(PointerType type) |
|||
{ |
|||
return type switch |
|||
{ |
|||
PointerType.Touch => new(10, 10), |
|||
_ => new(4, 4), |
|||
}; |
|||
} |
|||
public Size GetDoubleTapSize(PointerType type) |
|||
{ |
|||
return type switch |
|||
{ |
|||
PointerType.Touch => new(16, 16), |
|||
_ => new(4, 4), |
|||
}; |
|||
} |
|||
public TimeSpan GetDoubleTapTime(PointerType type) => TimeSpan.FromMilliseconds(500); |
|||
} |
|||
} |
|||
@ -1,17 +0,0 @@ |
|||
using System; |
|||
using Avalonia.Platform; |
|||
|
|||
namespace Avalonia.X11 |
|||
{ |
|||
class PlatformSettingsStub : IPlatformSettings |
|||
{ |
|||
public Size DoubleClickSize { get; } = new Size(2, 2); |
|||
public TimeSpan DoubleClickTime { get; } = TimeSpan.FromMilliseconds(500); |
|||
|
|||
/// <inheritdoc cref="IPlatformSettings.TouchDoubleClickSize"/>
|
|||
public Size TouchDoubleClickSize => new Size(16, 16); |
|||
|
|||
/// <inheritdoc cref="IPlatformSettings.TouchDoubleClickTime"/>
|
|||
public TimeSpan TouchDoubleClickTime => DoubleClickTime; |
|||
} |
|||
} |
|||
@ -0,0 +1,110 @@ |
|||
using System; |
|||
using Avalonia.Input; |
|||
using Avalonia.Input.Raw; |
|||
using Avalonia.Logging; |
|||
using static Avalonia.LinuxFramebuffer.Input.LibInput.LibInputNativeUnsafeMethods; |
|||
|
|||
namespace Avalonia.LinuxFramebuffer.Input.LibInput; |
|||
|
|||
public partial class LibInputBackend |
|||
{ |
|||
private MouseDevice _mouse = new MouseDevice(); |
|||
private Point _mousePosition; |
|||
private const string Pointer = LibInput + "/" + nameof(Pointer); |
|||
|
|||
private void HandlePointer(IntPtr ev, LibInputEventType type) |
|||
{ |
|||
var modifiers = RawInputModifiers.None; //TODO: support input modifiers
|
|||
var pev = libinput_event_get_pointer_event(ev); |
|||
var info = _screen.ScaledSize; |
|||
var ts = libinput_event_pointer_get_time_usec(pev) / 1000; |
|||
switch (type) |
|||
{ |
|||
case LibInputEventType.LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE: |
|||
_mousePosition = new Point(libinput_event_pointer_get_absolute_x_transformed(pev, (int)info.Width), |
|||
libinput_event_pointer_get_absolute_y_transformed(pev, (int)info.Height)); |
|||
ScheduleInput(new RawPointerEventArgs(_mouse, ts, _inputRoot, RawPointerEventType.Move, _mousePosition, |
|||
modifiers)); |
|||
break; |
|||
case LibInputEventType.LIBINPUT_EVENT_POINTER_BUTTON: |
|||
{ |
|||
var button = (EvKey)libinput_event_pointer_get_button(pev); |
|||
var buttonState = libinput_event_pointer_get_button_state(pev); |
|||
|
|||
RawPointerEventArgs evnt = button switch |
|||
{ |
|||
EvKey.BTN_LEFT when buttonState == 1 |
|||
=> new(_mouse, ts, _inputRoot, RawPointerEventType.LeftButtonDown, _mousePosition, modifiers), |
|||
EvKey.BTN_LEFT when buttonState == 0 |
|||
=> new(_mouse, ts, _inputRoot, RawPointerEventType.LeftButtonUp, _mousePosition, modifiers), |
|||
EvKey.BTN_RIGHT when buttonState == 1 |
|||
=> new(_mouse, ts, _inputRoot, RawPointerEventType.RightButtonUp, _mousePosition, modifiers), |
|||
EvKey.BTN_RIGHT when buttonState == 2 |
|||
=> new(_mouse, ts, _inputRoot, RawPointerEventType.RightButtonDown, _mousePosition, modifiers), |
|||
EvKey.BTN_MIDDLE when buttonState == 1 |
|||
=> new(_mouse, ts, _inputRoot, RawPointerEventType.MiddleButtonDown, _mousePosition, modifiers), |
|||
EvKey.BTN_MIDDLE when buttonState == 2 |
|||
=> new(_mouse, ts, _inputRoot, RawPointerEventType.MiddleButtonUp, _mousePosition, modifiers), |
|||
_ => default, |
|||
}; |
|||
if (evnt is not null) |
|||
{ |
|||
ScheduleInput(evnt); |
|||
} |
|||
else |
|||
{ |
|||
Logger.TryGet(LogEventLevel.Warning, Pointer) |
|||
?.Log(this, $"The button {button} is not associated"); |
|||
} |
|||
} |
|||
break; |
|||
// Backward compatibility with low-res wheel
|
|||
case LibInputEventType.LIBINPUT_EVENT_POINTER_AXIS: |
|||
{ |
|||
var sourceAxis = libinput_event_pointer_get_axis_source(pev); |
|||
switch (sourceAxis) |
|||
{ |
|||
case LibInputPointerAxisSource.LIBINPUT_POINTER_AXIS_SOURCE_WHEEL: |
|||
{ |
|||
var value = libinput_event_pointer_get_axis_value_discrete(pev, |
|||
LibInputPointerAxis.LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL); |
|||
ScheduleInput(new RawMouseWheelEventArgs(_mouse |
|||
, ts |
|||
, _inputRoot |
|||
, _mousePosition |
|||
, new Vector(0, -value) |
|||
, modifiers)); |
|||
} |
|||
break; |
|||
case LibInputPointerAxisSource.LIBINPUT_POINTER_AXIS_SOURCE_FINGER: |
|||
case LibInputPointerAxisSource.LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS: |
|||
case LibInputPointerAxisSource.LIBINPUT_POINTER_AXIS_SOURCE_WHEEL_TILT: |
|||
default: |
|||
Logger.TryGet(LogEventLevel.Debug, Pointer) |
|||
?.Log(this, $"The pointer axis {sourceAxis} is not managed."); |
|||
break; |
|||
} |
|||
} |
|||
break; |
|||
// Hi-Res wheel
|
|||
case LibInputEventType.LIBINPUT_EVENT_POINTER_SCROLL_WHEEL: |
|||
{ |
|||
var value = new Vector(0, |
|||
-libinput_event_pointer_get_scroll_value_v120(pev, |
|||
LibInputPointerAxis.LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL) / 120); |
|||
ScheduleInput(new RawMouseWheelEventArgs(_mouse |
|||
, ts |
|||
, _inputRoot |
|||
, _mousePosition |
|||
, value |
|||
, modifiers)); |
|||
} |
|||
break; |
|||
default: |
|||
Logger.TryGet(LogEventLevel.Warning, Pointer) |
|||
?.Log(this, $"The pointer event {type} is not mapped."); |
|||
break; |
|||
} |
|||
|
|||
} |
|||
} |
|||
@ -0,0 +1,175 @@ |
|||
using System; |
|||
using System.Threading; |
|||
using OpenQA.Selenium.Appium; |
|||
using OpenQA.Selenium.Interactions; |
|||
using Xunit; |
|||
|
|||
namespace Avalonia.IntegrationTests.Appium |
|||
{ |
|||
[Collection("Default")] |
|||
public class GestureTests |
|||
{ |
|||
private readonly AppiumDriver<AppiumWebElement> _session; |
|||
|
|||
public GestureTests(TestAppFixture fixture) |
|||
{ |
|||
_session = fixture.Session; |
|||
|
|||
var tabs = _session.FindElementByAccessibilityId("MainTabs"); |
|||
var tab = tabs.FindElementByName("Gestures"); |
|||
tab.Click(); |
|||
var clear = _session.FindElementByAccessibilityId("ResetGestures"); |
|||
clear.Click(); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Tapped_Is_Raised() |
|||
{ |
|||
var border = _session.FindElementByAccessibilityId("GestureBorder"); |
|||
var lastGesture = _session.FindElementByAccessibilityId("LastGesture"); |
|||
|
|||
new Actions(_session).Click(border).Perform(); |
|||
|
|||
Assert.Equal("Tapped", lastGesture.Text); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Tapped_Is_Raised_Slow() |
|||
{ |
|||
var border = _session.FindElementByAccessibilityId("GestureBorder"); |
|||
var lastGesture = _session.FindElementByAccessibilityId("LastGesture"); |
|||
|
|||
new Actions(_session).ClickAndHold(border).Perform(); |
|||
|
|||
Thread.Sleep(2000); |
|||
|
|||
new Actions(_session).Release(border).Perform(); |
|||
|
|||
Assert.Equal("Tapped", lastGesture.Text); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Tapped_Is_Not_Raised_For_Drag() |
|||
{ |
|||
var border = _session.FindElementByAccessibilityId("GestureBorder"); |
|||
var lastGesture = _session.FindElementByAccessibilityId("LastGesture"); |
|||
|
|||
new Actions(_session) |
|||
.ClickAndHold(border) |
|||
.MoveByOffset(50, 50) |
|||
.Release() |
|||
.Perform(); |
|||
|
|||
Assert.Equal(string.Empty, lastGesture.Text); |
|||
} |
|||
|
|||
[Fact] |
|||
public void DoubleTapped_Is_Raised() |
|||
{ |
|||
var border = _session.FindElementByAccessibilityId("GestureBorder"); |
|||
var lastGesture = _session.FindElementByAccessibilityId("LastGesture"); |
|||
|
|||
new Actions(_session).DoubleClick(border).Perform(); |
|||
|
|||
Assert.Equal("DoubleTapped", lastGesture.Text); |
|||
} |
|||
|
|||
[Fact] |
|||
public void DoubleTapped_Is_Raised_2() |
|||
{ |
|||
var border = _session.FindElementByAccessibilityId("GestureBorder"); |
|||
var lastGesture = _session.FindElementByAccessibilityId("LastGesture"); |
|||
|
|||
new Actions(_session).ClickAndHold(border).Release().Perform(); |
|||
|
|||
Thread.Sleep(100); |
|||
|
|||
// DoubleTapped is raised on second pointer press, not release.
|
|||
new Actions(_session).ClickAndHold(border).Perform(); |
|||
|
|||
try |
|||
{ |
|||
Assert.Equal("DoubleTapped", lastGesture.Text); |
|||
} |
|||
finally |
|||
{ |
|||
new Actions(_session).Release(border).Perform(); |
|||
} |
|||
} |
|||
|
|||
[Fact] |
|||
public void DoubleTapped_Is_Raised_Not_Raised_If_Too_Slow() |
|||
{ |
|||
var border = _session.FindElementByAccessibilityId("GestureBorder"); |
|||
var lastGesture = _session.FindElementByAccessibilityId("LastGesture"); |
|||
|
|||
new Actions(_session).ClickAndHold(border).Release().Perform(); |
|||
|
|||
Thread.Sleep(2000); |
|||
|
|||
new Actions(_session).ClickAndHold(border).Release().Perform(); |
|||
|
|||
Assert.Equal("Tapped", lastGesture.Text); |
|||
} |
|||
|
|||
[Fact] |
|||
public void DoubleTapped_Is_Raised_After_Control_Changes() |
|||
{ |
|||
// #8733
|
|||
var border = _session.FindElementByAccessibilityId("GestureBorder"); |
|||
var lastGesture = _session.FindElementByAccessibilityId("LastGesture"); |
|||
|
|||
new Actions(_session) |
|||
.MoveToElement(border) |
|||
.DoubleClick() |
|||
.DoubleClick() |
|||
.Perform(); |
|||
|
|||
Assert.Equal("DoubleTapped2", lastGesture.Text); |
|||
} |
|||
|
|||
[Fact] |
|||
public void RightTapped_Is_Raised() |
|||
{ |
|||
var border = _session.FindElementByAccessibilityId("GestureBorder"); |
|||
var lastGesture = _session.FindElementByAccessibilityId("LastGesture"); |
|||
|
|||
new Actions(_session).ContextClick(border).Perform(); |
|||
|
|||
Assert.Equal("RightTapped", lastGesture.Text); |
|||
} |
|||
|
|||
[PlatformFact(TestPlatforms.MacOS)] |
|||
public void RightTapped_Is_Raised_2() |
|||
{ |
|||
var border = _session.FindElementByAccessibilityId("GestureBorder"); |
|||
var lastGesture = _session.FindElementByAccessibilityId("LastGesture"); |
|||
var device = new PointerInputDevice(PointerKind.Mouse); |
|||
var b = new ActionBuilder(); |
|||
|
|||
b.AddAction(device.CreatePointerMove(border, 50, 50, TimeSpan.FromMilliseconds(100))); |
|||
b.AddAction(device.CreatePointerDown(MouseButton.Right)); |
|||
b.AddAction(device.CreatePointerMove(border, 2, 2, TimeSpan.FromMilliseconds(100))); |
|||
b.AddAction(device.CreatePointerUp(MouseButton.Right)); |
|||
_session.PerformActions(b.ToActionSequenceList()); |
|||
|
|||
Assert.Equal("RightTapped", lastGesture.Text); |
|||
} |
|||
|
|||
[PlatformFact(TestPlatforms.MacOS)] |
|||
public void RightTapped_Is_Not_Raised_For_Drag() |
|||
{ |
|||
var border = _session.FindElementByAccessibilityId("GestureBorder"); |
|||
var lastGesture = _session.FindElementByAccessibilityId("LastGesture"); |
|||
var device = new PointerInputDevice(PointerKind.Mouse); |
|||
var b = new ActionBuilder(); |
|||
|
|||
b.AddAction(device.CreatePointerMove(border, 50, 50, TimeSpan.FromMilliseconds(100))); |
|||
b.AddAction(device.CreatePointerDown(MouseButton.Right)); |
|||
b.AddAction(device.CreatePointerMove(CoordinateOrigin.Pointer, 50, 50, TimeSpan.FromMilliseconds(100))); |
|||
b.AddAction(device.CreatePointerUp(MouseButton.Right)); |
|||
|
|||
Assert.Equal(string.Empty, lastGesture.Text); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue