Browse Source

Primary mouse device (#19898) (#19990)

* Primary mouse device

* Addressing feedback

---------

Co-authored-by: Jan Kučera <miloush@users.noreply.github.com>
Co-authored-by: Julien Lebosquain <julien@lebosquain.net>
pull/20076/head
Jan Kučera 3 months ago
committed by GitHub
parent
commit
bde2c99b95
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 15
      src/Avalonia.Base/Input/MouseDevice.cs
  2. 4
      src/Avalonia.Native/TopLevelImpl.cs
  3. 3
      src/Avalonia.X11/X11Window.cs
  4. 31
      src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs
  5. 6
      src/Windows/Avalonia.Win32/WindowImpl.cs

15
src/Avalonia.Base/Input/MouseDevice.cs

@ -18,6 +18,9 @@ namespace Avalonia.Input
[PrivateApi]
public class MouseDevice : IMouseDevice, IDisposable
{
private static MouseDevice? _primary;
internal static MouseDevice Primary => _primary ??= new MouseDevice();
private int _clickCount;
private Rect _lastClickRect;
private ulong _lastClickTime;
@ -31,6 +34,16 @@ namespace Avalonia.Input
_pointer = pointer ?? new Pointer(Pointer.GetNextFreeId(), PointerType.Mouse, true);
}
internal static TMouseDevice GetOrCreatePrimary<TMouseDevice>() where TMouseDevice : MouseDevice, new()
{
if (_primary is TMouseDevice device)
return device;
device = new TMouseDevice();
_primary = device;
return device;
}
public void ProcessRawEvent(RawInputEventArgs e)
{
if (!e.Handled && e is RawPointerEventArgs margs)
@ -300,6 +313,8 @@ namespace Avalonia.Input
public void Dispose()
{
System.Diagnostics.Debug.Assert(this != _primary, "Disposing primary mouse device.");
_disposed = true;
_pointer?.Dispose();
}

4
src/Avalonia.Native/TopLevelImpl.cs

@ -89,7 +89,7 @@ internal class TopLevelImpl : ITopLevelImpl, IFramebufferPlatformSurface
Factory = factory;
_keyboard = AvaloniaLocator.Current.GetService<IKeyboardDevice>();
_mouse = new MouseDevice();
_mouse = Avalonia.Input.MouseDevice.Primary;
_pen = new PenDevice();
_cursorFactory = AvaloniaLocator.Current.GetService<ICursorFactory>();
}
@ -387,8 +387,6 @@ internal class TopLevelImpl : ITopLevelImpl, IFramebufferPlatformSurface
_nativeControlHost?.Dispose();
_nativeControlHost = null;
_mouse?.Dispose();
}
protected virtual bool ChromeHitTest(RawPointerEventArgs e)

3
src/Avalonia.X11/X11Window.cs

@ -96,7 +96,7 @@ namespace Avalonia.X11
_popup = popupParent != null;
_overrideRedirect = _popup || overrideRedirect;
_x11 = platform.Info;
_mouse = new MouseDevice();
_mouse = Avalonia.Input.MouseDevice.Primary;
_touch = new TouchDevice();
_keyboard = platform.KeyboardDevice;
@ -1077,7 +1077,6 @@ namespace Avalonia.X11
_platform.XI2?.OnWindowDestroyed(_handle);
var handle = _handle;
_handle = IntPtr.Zero;
_mouse.Dispose();
_touch.Dispose();
if (!fromDestroyNotification)
XDestroyWindow(_x11.Display, handle);

31
src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs

@ -114,9 +114,9 @@ namespace Avalonia.Win32
//Window doesn't exist anymore
_hwnd = IntPtr.Zero;
//Remove root reference to this class, so unmanaged delegate can be collected
s_instances.Remove(this);
lock (s_instances)
s_instances.Remove(this);
_mouseDevice.Dispose();
_touchDevice.Dispose();
//Free other resources
Dispose();
@ -280,14 +280,6 @@ namespace Avalonia.Win32
DipFromLParam(lParam), GetMouseModifiers(wParam));
break;
}
// Mouse capture is lost
case WindowsMessage.WM_CANCELMODE:
if (!IsMouseInPointerEnabled)
{
_mouseDevice.Capture(null);
}
break;
case WindowsMessage.WM_MOUSEMOVE:
{
@ -394,13 +386,14 @@ namespace Avalonia.Win32
break;
}
// covers WM_CANCELMODE which sends WM_CAPTURECHANGED in DefWindowProc
case WindowsMessage.WM_CAPTURECHANGED:
{
if (IsMouseInPointerEnabled)
{
break;
}
if (_hwnd != lParam)
if (!IsOurWindow(lParam))
{
_trackingMouse = false;
e = new RawPointerEventArgs(
@ -907,6 +900,22 @@ namespace Avalonia.Win32
return DefWindowProc(hWnd, msg, wParam, lParam);
}
private bool IsOurWindow(IntPtr hwnd)
{
if (hwnd == IntPtr.Zero)
return false;
if (hwnd == _hwnd)
return true;
lock (s_instances)
for (int i = 0; i < s_instances.Count; i++)
if (s_instances[i]._hwnd == hwnd)
return true;
return false;
}
private void OnShowHideMessage(bool shown)
{
_shown = shown;

6
src/Windows/Avalonia.Win32/WindowImpl.cs

@ -119,7 +119,7 @@ namespace Avalonia.Win32
public WindowImpl()
{
_touchDevice = new TouchDevice();
_mouseDevice = new WindowsMouseDevice();
_mouseDevice = Avalonia.Input.MouseDevice.GetOrCreatePrimary<WindowsMouseDevice>();
_penDevice = new PenDevice();
#if USE_MANAGED_DRAG
@ -177,7 +177,9 @@ namespace Avalonia.Win32
_nativeControlHost = new Win32NativeControlHost(this, !UseRedirectionBitmap);
_defaultTransparencyLevel = UseRedirectionBitmap ? WindowTransparencyLevel.None : WindowTransparencyLevel.Transparent;
_transparencyLevel = _defaultTransparencyLevel;
s_instances.Add(this);
lock (s_instances)
s_instances.Add(this);
}
internal IInputRoot Owner

Loading…
Cancel
Save