Skip to content

Commit

Permalink
Added Ctrl+Click support for opening context menu on mac
Browse files Browse the repository at this point in the history
  • Loading branch information
herman-kirshin committed May 29, 2024
1 parent 2cb40ac commit d907e96
Show file tree
Hide file tree
Showing 14 changed files with 143 additions and 3 deletions.
1 change: 1 addition & 0 deletions src/Android/Avalonia.Android/AndroidPlatform.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ public static void Initialize()
.Bind<IPlatformThreadingInterface>().ToConstant(new AndroidThreadingInterface())
.Bind<IPlatformIconLoader>().ToSingleton<PlatformIconLoaderStub>()
.Bind<IRenderTimer>().ToConstant(new ChoreographerTimer())
.Bind<PlatformPointerConfiguration>().ToSingleton<PlatformPointerConfiguration>()
.Bind<PlatformHotkeyConfiguration>().ToSingleton<PlatformHotkeyConfiguration>()
.Bind<IActivatableLifetime>().ToConstant(new AndroidActivatableLifetime());

Expand Down
24 changes: 24 additions & 0 deletions src/Avalonia.Base/Input/Platform/PlatformPointerConfiguration.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System.Collections.Generic;
using Avalonia.Metadata;

namespace Avalonia.Input.Platform;

public sealed class PlatformPointerConfiguration
{
public List<PointerGesture> OpenContextMenu { get; set; }

[PrivateApi]
public PlatformPointerConfiguration()
{
OpenContextMenu = new List<PointerGesture>
{
new PointerGesture(MouseButton.Right, KeyModifiers.None)
};
}

[PrivateApi]
public PlatformPointerConfiguration(params PointerGesture[] additionalContextGestures) : this()
{
OpenContextMenu.AddRange(additionalContextGestures);
}
}
103 changes: 103 additions & 0 deletions src/Avalonia.Base/Input/PointerGesture.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
using System;
using System.Text;
using Avalonia.VisualTree;

namespace Avalonia.Input;

public class PointerGesture : IEquatable<PointerGesture>
{
public PointerGesture(MouseButton button, KeyModifiers modifiers = KeyModifiers.None)
{
Button = button;
KeyModifiers = modifiers;
}

public bool Equals(PointerGesture? other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;

return Button == other.Button && KeyModifiers == other.KeyModifiers;
}

public override bool Equals(object? obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;

return obj is KeyGesture gesture && Equals(gesture);
}

public override int GetHashCode()
{
unchecked
{
return ((int)Button * 397) ^ (int)KeyModifiers;
}
}

public static bool operator ==(PointerGesture? left, PointerGesture? right)
{
return Equals(left, right);
}

public static bool operator !=(PointerGesture? left, PointerGesture? right)
{
return !Equals(left, right);
}

public MouseButton Button { get; }

public KeyModifiers KeyModifiers { get; }

public override string ToString()
{
var s = new StringBuilder();

static void Plus(StringBuilder s)
{
if (s.Length > 0)
{
s.Append("+");
}
}

if (KeyModifiers.HasAllFlags(KeyModifiers.Control))
{
s.Append("Ctrl");
}

if (KeyModifiers.HasAllFlags(KeyModifiers.Shift))
{
Plus(s);
s.Append("Shift");
}

if (KeyModifiers.HasAllFlags(KeyModifiers.Alt))
{
Plus(s);
s.Append("Alt");
}

if (KeyModifiers.HasAllFlags(KeyModifiers.Meta))
{
Plus(s);
s.Append("Cmd");
}

Plus(s);
s.Append(Button);

return s.ToString();
}

public bool Matches(PointerEventArgs pointerEvent) =>
pointerEvent != null &&
pointerEvent.KeyModifiers == KeyModifiers &&
pointerEvent.GetCurrentPoint(pointerEvent.Source as Visual).Properties.PointerUpdateKind.GetMouseButton() == Button;

public bool Matches(PointerReleasedEventArgs pointerEvent) =>
pointerEvent != null &&
pointerEvent.KeyModifiers == KeyModifiers &&
pointerEvent.InitialPressMouseButton == Button;
}
2 changes: 1 addition & 1 deletion src/Avalonia.Controls/Button.cs
Original file line number Diff line number Diff line change
Expand Up @@ -419,7 +419,7 @@ protected override void OnPointerReleased(PointerReleasedEventArgs e)
{
base.OnPointerReleased(e);

if (IsPressed && e.InitialPressMouseButton == MouseButton.Left)
if (!e.Handled && IsPressed && e.InitialPressMouseButton == MouseButton.Left)
{
IsPressed = false;
e.Handled = true;
Expand Down
5 changes: 4 additions & 1 deletion src/Avalonia.Controls/Control.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using Avalonia.Automation.Peers;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Templates;
Expand Down Expand Up @@ -480,9 +481,11 @@ protected override void OnPointerReleased(PointerReleasedEventArgs e)
{
base.OnPointerReleased(e);

var contextGestures = AvaloniaLocator.Current.GetService<PlatformPointerConfiguration>()?.OpenContextMenu;

if (e.Source == this
&& !e.Handled
&& e.InitialPressMouseButton == MouseButton.Right)
&& contextGestures?.Any(x => x.Matches(e)) == true)
{
var args = new ContextRequestedEventArgs(e);
RaiseEvent(args);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ public static void Initialize(IAvaloniaRemoteTransportConnection transport)
.Bind<IRenderTimer>().ToConstant(new UiThreadRenderTimer(60))
.Bind<IWindowingPlatform>().ToConstant(instance)
.Bind<IPlatformIconLoader>().ToSingleton<IconLoaderStub>()
.Bind<PlatformPointerConfiguration>().ToSingleton<PlatformPointerConfiguration>()
.Bind<PlatformHotkeyConfiguration>().ToSingleton<PlatformHotkeyConfiguration>();

}
Expand Down
3 changes: 2 additions & 1 deletion src/Avalonia.Native/AvaloniaNativePlatform.cs
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,8 @@ void DoInitialize(AvaloniaNativePlatformOptions options)
hotkeys.MoveCursorToTheEndOfLine.Add(new KeyGesture(Key.Right, hotkeys.CommandModifiers));
hotkeys.MoveCursorToTheEndOfLineWithSelection.Add(new KeyGesture(Key.Right, hotkeys.CommandModifiers | hotkeys.SelectionModifiers));

AvaloniaLocator.CurrentMutable.Bind<PlatformHotkeyConfiguration>().ToConstant(hotkeys);
AvaloniaLocator.CurrentMutable.Bind<PlatformHotkeyConfiguration>().ToConstant(hotkeys)
.Bind<PlatformPointerConfiguration>().ToConstant(new PlatformPointerConfiguration(new PointerGesture(MouseButton.Left, KeyModifiers.Control)));;

foreach (var mode in _options.RenderingMode)
{
Expand Down
1 change: 1 addition & 0 deletions src/Avalonia.X11/X11Platform.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ public void Initialize(X11PlatformOptions options)
.Bind<IWindowingPlatform>().ToConstant(this)
.Bind<IDispatcherImpl>().ToConstant(new X11PlatformThreading(this))
.Bind<IRenderTimer>().ToConstant(timer)
.Bind<PlatformPointerConfiguration>().ToSingleton<PlatformPointerConfiguration>()
.Bind<PlatformHotkeyConfiguration>().ToConstant(new PlatformHotkeyConfiguration(KeyModifiers.Control))
.Bind<IKeyboardDevice>().ToFunc(() => KeyboardDevice)
.Bind<ICursorFactory>().ToConstant(new X11CursorFactory(Display))
Expand Down
1 change: 1 addition & 0 deletions src/Browser/Avalonia.Browser/WindowingPlatform.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ public static void Register()
.Bind<IPlatformSettings>().ToSingleton<BrowserPlatformSettings>()
.Bind<IWindowingPlatform>().ToConstant(instance)
.Bind<IPlatformIconLoader>().ToSingleton<IconLoaderStub>()
.Bind<PlatformPointerConfiguration>().ToSingleton<PlatformPointerConfiguration>()
.Bind<PlatformHotkeyConfiguration>().ToSingleton<PlatformHotkeyConfiguration>()
.Bind<IActivatableLifetime>().ToSingleton<BrowserActivatableLifetime>();
AvaloniaLocator.CurrentMutable.Bind<IDispatcherImpl>().ToSingleton<BrowserDispatcherImpl>();
Expand Down
1 change: 1 addition & 0 deletions src/Headless/Avalonia.Headless/AvaloniaHeadlessPlatform.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ internal static void Initialize(AvaloniaHeadlessPlatformOptions opts)
.Bind<IKeyboardDevice>().ToConstant(new KeyboardDevice())
.Bind<IRenderTimer>().ToConstant(new RenderTimer(60))
.Bind<IWindowingPlatform>().ToConstant(new HeadlessWindowingPlatform(opts.FrameBufferFormat))
.Bind<PlatformPointerConfiguration>().ToSingleton<PlatformPointerConfiguration>()
.Bind<PlatformHotkeyConfiguration>().ToSingleton<PlatformHotkeyConfiguration>();
Compositor = new Compositor( null);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ void Initialize()
.Bind<IKeyboardDevice>().ToConstant(new KeyboardDevice())
.Bind<IPlatformIconLoader>().ToSingleton<LinuxFramebufferIconLoaderStub>()
.Bind<IPlatformSettings>().ToSingleton<DefaultPlatformSettings>()
.Bind<PlatformPointerConfiguration>().ToSingleton<PlatformPointerConfiguration>()
.Bind<PlatformHotkeyConfiguration>().ToSingleton<PlatformHotkeyConfiguration>();

Compositor = new Compositor(AvaloniaLocator.Current.GetService<IPlatformGraphics>());
Expand Down
1 change: 1 addition & 0 deletions src/Windows/Avalonia.Win32/Win32Platform.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ public static void Initialize(Win32PlatformOptions options)
.Bind<IDispatcherImpl>().ToConstant(s_instance._dispatcher)
.Bind<IRenderTimer>().ToConstant(renderTimer)
.Bind<IWindowingPlatform>().ToConstant(s_instance)
.Bind<PlatformPointerConfiguration>().ToSingleton<PlatformPointerConfiguration>()
.Bind<PlatformHotkeyConfiguration>().ToConstant(new PlatformHotkeyConfiguration(KeyModifiers.Control)
{
OpenContextMenu =
Expand Down
1 change: 1 addition & 0 deletions src/iOS/Avalonia.iOS/Platform.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ public static void Register(IAvaloniaAppDelegate? appDelegate)
.Bind<IWindowingPlatform>().ToConstant(new WindowingPlatformStub())
.Bind<IPlatformSettings>().ToSingleton<PlatformSettings>()
.Bind<IPlatformIconLoader>().ToConstant(new PlatformIconLoaderStub())
.Bind<PlatformPointerConfiguration>().ToSingleton<PlatformPointerConfiguration>()
.Bind<PlatformHotkeyConfiguration>().ToSingleton<PlatformHotkeyConfiguration>()
.Bind<IRenderTimer>().ToConstant(Timer)
.Bind<IDispatcherImpl>().ToConstant(DispatcherImpl.Instance)
Expand Down
1 change: 1 addition & 0 deletions tests/Avalonia.UnitTests/UnitTestApplication.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ public override void RegisterServices()
.Bind<IDispatcherImpl>().ToConstant(Services.DispatcherImpl)
.Bind<ICursorFactory>().ToConstant(Services.StandardCursorFactory)
.Bind<IWindowingPlatform>().ToConstant(Services.WindowingPlatform)
.Bind<PlatformPointerConfiguration>().ToSingleton<PlatformPointerConfiguration>()
.Bind<PlatformHotkeyConfiguration>().ToSingleton<PlatformHotkeyConfiguration>()
.Bind<IPlatformSettings>().ToSingleton<DefaultPlatformSettings>()
.Bind<IAccessKeyHandler>().ToConstant(Services.AccessKeyHandler)
Expand Down

0 comments on commit d907e96

Please sign in to comment.