From f1d20dc2bc1a3816b719f33d77db0bc9125afa60 Mon Sep 17 00:00:00 2001 From: Rolf Bjarne Kvinge Date: Wed, 27 Oct 2021 10:24:56 +0200 Subject: [PATCH] [CGEvent] Subclass NativeObject + numerous other code updates (#13122) * Subclass NativeObject to reuse object lifetime code. * Enable nullability and fix code accordingly. * Use 'is' and 'is not' instead of '==' and '!=' for object identity. * Use the null-safe NativeObjectExtensions.GetHandle extension method to get the handle instead of checking for null (avoids some code duplication). * Use 'nameof (parameter)' instead of string constants. * Remove the (IntPtr) constructor for XAMCORE_4_0. --- src/CoreGraphics/CGEvent.cs | 188 +++++++++++++++++------------------- 1 file changed, 87 insertions(+), 101 deletions(-) diff --git a/src/CoreGraphics/CGEvent.cs b/src/CoreGraphics/CGEvent.cs index 80e4eb425f..9f69a2345e 100644 --- a/src/CoreGraphics/CGEvent.cs +++ b/src/CoreGraphics/CGEvent.cs @@ -8,14 +8,14 @@ * Miguel de Icaza */ +#nullable enable + #if MONOMAC || __MACCATALYST__ using System; using System.Runtime.InteropServices; using System.Runtime.Versioning; -#if !NO_SYSTEM_DRAWING -using System.Drawing; -#endif + using CoreFoundation; using ObjCRuntime; using Foundation; @@ -27,77 +27,81 @@ namespace CoreGraphics { #else [SupportedOSPlatform ("maccatalyst15.0")] #endif - public sealed class CGEvent : IDisposable, INativeObject { + public sealed class CGEvent : NativeObject { public delegate IntPtr CGEventTapCallback (IntPtr tapProxyEvent, CGEventType eventType, IntPtr eventRef, IntPtr userInfo); [DllImport (Constants.ApplicationServicesCoreGraphicsLibrary)] extern static IntPtr CGEventTapCreate (CGEventTapLocation location, CGEventTapPlacement place, CGEventTapOptions options, CGEventMask mask, CGEventTapCallback cback, IntPtr data); - public static CFMachPort CreateTap (CGEventTapLocation location, CGEventTapPlacement place, CGEventTapOptions options, CGEventMask mask, CGEventTapCallback cback, IntPtr data) + public static CFMachPort? CreateTap (CGEventTapLocation location, CGEventTapPlacement place, CGEventTapOptions options, CGEventMask mask, CGEventTapCallback cback, IntPtr data) { var r = CGEventTapCreate (location, place, options, mask, cback, data); if (r == IntPtr.Zero) return null; - return new CFMachPort (r); + return new CFMachPort (r, true); } [DllImport (Constants.ApplicationServicesCoreGraphicsLibrary)] extern static IntPtr CGEventTapCreateForPSN (IntPtr processSerialNumer, CGEventTapLocation location, CGEventTapPlacement place, CGEventTapOptions options, CGEventMask mask, CGEventTapCallback cback, IntPtr data); - public static CFMachPort CreateTap (IntPtr processSerialNumber, CGEventTapLocation location, CGEventTapPlacement place, CGEventTapOptions options, CGEventMask mask, CGEventTapCallback cback, IntPtr data) + public static CFMachPort? CreateTap (IntPtr processSerialNumber, CGEventTapLocation location, CGEventTapPlacement place, CGEventTapOptions options, CGEventMask mask, CGEventTapCallback cback, IntPtr data) { var r = CGEventTapCreateForPSN (processSerialNumber, location, place, options, mask, cback, data); if (r == IntPtr.Zero) return null; - return new CFMachPort (r); + return new CFMachPort (r, true); } - - IntPtr handle; [DllImport (Constants.ApplicationServicesCoreGraphicsLibrary)] extern static IntPtr CGEventCreateFromData (IntPtr allocator, IntPtr nsdataSource); - public CGEvent (NSData source) + static IntPtr Create (NSData source) { - if (source == null) - throw new ArgumentNullException ("source"); + if (source is null) + throw new ArgumentNullException (nameof (source)); - handle = CGEventCreateFromData (IntPtr.Zero, source.Handle); + return CGEventCreateFromData (IntPtr.Zero, source.Handle); + } + + public CGEvent (NSData source) + : base (Create (source), true) + { } [DllImport (Constants.ApplicationServicesCoreGraphicsLibrary)] extern static IntPtr CGEventCreate (IntPtr eventSourceHandle); - public CGEvent (CGEventSource eventSource) - { - handle = CGEventCreate (eventSource == null ? IntPtr.Zero : eventSource.Handle); - } - - public CGEvent (IntPtr handle) : this (handle, false) + public CGEvent (CGEventSource? eventSource) + : base (CGEventCreate (eventSource.GetHandle ()), true) { } - internal CGEvent (IntPtr handle, bool ownsHandle) +#if !XAMCORE_4_0 + public CGEvent (IntPtr handle) + : base (handle, false) + { + } +#endif + + internal CGEvent (IntPtr handle, bool owns) + : base (handle, owns) { - if (!ownsHandle) - CFObject.CFRetain (handle); - this.handle = handle; } [DllImport (Constants.ApplicationServicesCoreGraphicsLibrary)] extern static IntPtr CGEventCreateMouseEvent(IntPtr source, CGEventType mouseType, CGPoint mouseCursorPosition, CGMouseButton mouseButton); - public CGEvent (CGEventSource source, CGEventType mouseType, CGPoint mouseCursorPosition, CGMouseButton mouseButton) + public CGEvent (CGEventSource? source, CGEventType mouseType, CGPoint mouseCursorPosition, CGMouseButton mouseButton) + : base (CGEventCreateMouseEvent (source.GetHandle (), mouseType, mouseCursorPosition, mouseButton), true) { - handle = CGEventCreateMouseEvent (source == null ? IntPtr.Zero : source.Handle, mouseType, mouseCursorPosition, mouseButton); } [DllImport (Constants.ApplicationServicesCoreGraphicsLibrary)] extern static IntPtr CGEventCreateKeyboardEvent (IntPtr source, ushort virtualKey, [MarshalAs (UnmanagedType.I1)] bool keyDown); - public CGEvent (CGEventSource source, ushort virtualKey, bool keyDown) + public CGEvent (CGEventSource? source, ushort virtualKey, bool keyDown) + : base (CGEventCreateKeyboardEvent (source.GetHandle (), virtualKey, keyDown), true) { - handle = CGEventCreateKeyboardEvent (source == null ? IntPtr.Zero : source.Handle, virtualKey, keyDown); } [DllImport (Constants.ApplicationServicesCoreGraphicsLibrary)] @@ -109,11 +113,13 @@ namespace CoreGraphics { [DllImport (Constants.ApplicationServicesCoreGraphicsLibrary)] extern static IntPtr CGEventCreateScrollWheelEvent (IntPtr source, CGScrollEventUnit units, uint /* uint32_t */ wheelCount, int /* uint32_t */ wheel1, int /* uint32_t */ wheel2, int /* uint32_t */ wheel3); - public CGEvent (CGEventSource source, CGScrollEventUnit units, params int [] wheel) + // This implementation doesn't work correctly on ARM64: https://github.com/xamarin/xamarin-macios/issues/13121 + static IntPtr Create (CGEventSource? source, CGScrollEventUnit units, params int [] wheel) { - IntPtr shandle = source == null ? IntPtr.Zero : source.Handle; - - switch (wheel.Length){ + IntPtr handle; + IntPtr shandle = source.GetHandle (); + + switch (wheel.Length) { case 0: throw new ArgumentException ("At least one wheel must be provided"); case 1: @@ -128,31 +134,12 @@ namespace CoreGraphics { default: throw new ArgumentException ("Only one to three wheels are supported on this constructor"); } - } - - ~CGEvent () - { - Dispose (false); + return handle; } - public IntPtr Handle { - get { - return handle; - } - } - - public void Dispose () + public CGEvent (CGEventSource source, CGScrollEventUnit units, params int [] wheel) + : base (Create (source, units, wheel), true) { - Dispose (true); - GC.SuppressFinalize (this); - } - - public void Dispose (bool disposing) - { - if (handle != IntPtr.Zero) { - CFObject.CFRelease (handle); - handle = IntPtr.Zero; - } } [DllImport (Constants.ApplicationServicesCoreGraphicsLibrary)] @@ -160,23 +147,23 @@ namespace CoreGraphics { public CGEvent Copy () { - return new CGEvent (CGEventCreateCopy (handle), true); + return new CGEvent (CGEventCreateCopy (Handle), true); } [DllImport (Constants.ApplicationServicesCoreGraphicsLibrary)] extern static IntPtr CGEventCreateData (IntPtr allocator, IntPtr handle); - public NSData ToData () + public NSData? ToData () { - return new NSData (CGEventCreateData (IntPtr.Zero, handle)); + return Runtime.GetNSObject (CGEventCreateData (IntPtr.Zero, Handle)); } [DllImport (Constants.ApplicationServicesCoreGraphicsLibrary)] extern static IntPtr CGEventCreateSourceFromEvent (IntPtr evthandle); - public CGEventSource CreateEventSource () + public CGEventSource? CreateEventSource () { - var esh = CGEventCreateSourceFromEvent (handle); + var esh = CGEventCreateSourceFromEvent (Handle); if (esh == IntPtr.Zero) return null; return new CGEventSource (esh, true); @@ -191,10 +178,10 @@ namespace CoreGraphics { public CGPoint Location { get { - return CGEventGetLocation (handle); + return CGEventGetLocation (Handle); } set { - CGEventSetLocation (handle, value); + CGEventSetLocation (Handle, value); } } @@ -203,7 +190,7 @@ namespace CoreGraphics { public CGPoint UnflippedLocation { get { - return CGEventGetUnflippedLocation (handle); + return CGEventGetUnflippedLocation (Handle); } } @@ -217,10 +204,10 @@ namespace CoreGraphics { public CGEventFlags Flags { get { - return GetFlags (handle); + return GetFlags (Handle); } set { - CGEventSetFlags (handle, value); + CGEventSetFlags (Handle, value); } } @@ -232,54 +219,54 @@ namespace CoreGraphics { internal long GetLong (CGEventField eventField) { - return GetLong (handle, (CGEventField) eventField); + return GetLong (Handle, eventField); } public long MouseEventNumber { get { - return GetLong (handle, CGEventField.MouseEventNumber); + return GetLong (Handle, CGEventField.MouseEventNumber); } } public long MouseEventClickState { get { - return GetLong (handle, CGEventField.MouseEventClickState); + return GetLong (Handle, CGEventField.MouseEventClickState); } } public double MouseEventPressure { get { - return GetDouble (handle, CGEventField.MouseEventPressure); + return GetDouble (Handle, CGEventField.MouseEventPressure); } } public long MouseEventButtonNumber { get { - return GetLong (handle, CGEventField.MouseEventButtonNumber); + return GetLong (Handle, CGEventField.MouseEventButtonNumber); } } public long MouseEventDeltaX { get { - return GetLong (handle, CGEventField.MouseEventDeltaX); + return GetLong (Handle, CGEventField.MouseEventDeltaX); } } public long MouseEventDeltaY { get { - return GetLong (handle, CGEventField.MouseEventDeltaY); + return GetLong (Handle, CGEventField.MouseEventDeltaY); } } public bool MouseEventInstantMouser { get { - return GetLong (handle, CGEventField.MouseEventButtonNumber) != 0; + return GetLong (Handle, CGEventField.MouseEventButtonNumber) != 0; } } public long MouseEventSubtype { get { - return GetLong (handle, CGEventField.MouseEventSubtype); + return GetLong (Handle, CGEventField.MouseEventSubtype); } } @@ -288,9 +275,9 @@ namespace CoreGraphics { public void SetEventSource (CGEventSource eventSource) { - if (eventSource == null) - throw new ArgumentNullException ("eventSource"); - CGEventSetSource (handle, eventSource.Handle); + if (eventSource is null) + throw new ArgumentNullException (nameof (eventSource)); + CGEventSetSource (Handle, eventSource.Handle); } [DllImport (Constants.ApplicationServicesCoreGraphicsLibrary)] @@ -301,10 +288,10 @@ namespace CoreGraphics { public CGEventType EventType { get { - return CGEventGetType (handle); + return CGEventGetType (Handle); } set { - CGEventSetType (handle, value); + CGEventSetType (Handle, value); } } @@ -319,20 +306,20 @@ namespace CoreGraphics { [Obsolete ("Use 'Timestamp' instead.")] public ulong Timestampe { get { - return CGEventGetTimestamp (handle); + return CGEventGetTimestamp (Handle); } set { - CGEventSetTimestamp (handle, value); + CGEventSetTimestamp (Handle, value); } } #endif public ulong Timestamp { get { - return CGEventGetTimestamp (handle); + return CGEventGetTimestamp (Handle); } set { - CGEventSetTimestamp (handle, value); + CGEventSetTimestamp (Handle, value); } } @@ -341,15 +328,15 @@ namespace CoreGraphics { public static void TapEnable (CFMachPort machPort) { - if (machPort == null) - throw new ArgumentNullException ("machPort"); + if (machPort is null) + throw new ArgumentNullException (nameof (machPort)); CGEventTapEnable (machPort.Handle, true); } public static void TapDisable (CFMachPort machPort) { - if (machPort == null) - throw new ArgumentNullException ("machPort"); + if (machPort is null) + throw new ArgumentNullException (nameof (machPort)); CGEventTapEnable (machPort.Handle, false); } @@ -359,8 +346,8 @@ namespace CoreGraphics { public static bool IsTapEnabled (CFMachPort machPort) { - if (machPort == null) - throw new ArgumentNullException ("machPort"); + if (machPort is null) + throw new ArgumentNullException (nameof (machPort)); return CGEventTapIsEnabled (machPort.Handle); } @@ -370,18 +357,18 @@ namespace CoreGraphics { public unsafe string GetUnicodeString () { char *buffer = stackalloc char [40]; - nuint actual; - - CGEventKeyboardGetUnicodeString (handle, 40, out actual, buffer); + CGEventKeyboardGetUnicodeString (Handle, 40, out var actual, buffer); return new String (buffer, 0, (int) actual); } [DllImport (Constants.ApplicationServicesCoreGraphicsLibrary)] unsafe extern static void CGEventKeyboardSetUnicodeString (IntPtr handle, nuint len, [MarshalAs(UnmanagedType.LPWStr)] string buffer); - public unsafe void SetUnicodeString (string value) + public void SetUnicodeString (string value) { - CGEventKeyboardSetUnicodeString (handle, (nuint) value.Length, value); + if (value is null) + throw new ArgumentNullException (nameof (value)); + CGEventKeyboardSetUnicodeString (Handle, (nuint) value.Length, value); } [DllImport (Constants.ApplicationServicesCoreGraphicsLibrary)] @@ -389,8 +376,8 @@ namespace CoreGraphics { public static void TapPostEven (IntPtr tapProxyEvent, CGEvent evt) { - if (evt == null) - throw new ArgumentNullException ("evt"); + if (evt is null) + throw new ArgumentNullException (nameof (evt)); CGEventTapPostEvent (tapProxyEvent, evt.Handle); } @@ -400,8 +387,8 @@ namespace CoreGraphics { public static void Post (CGEvent evt, CGEventTapLocation location) { - if (evt == null) - throw new ArgumentNullException ("evt"); + if (evt is null) + throw new ArgumentNullException (nameof (evt)); CGEventPost (location, evt.Handle); } @@ -411,12 +398,11 @@ namespace CoreGraphics { public static void PostToPSN (CGEvent evt, IntPtr processSerialNumber) { - if (evt == null) - throw new ArgumentNullException ("evt"); + if (evt is null) + throw new ArgumentNullException (nameof (evt)); CGEventPostToPSN (processSerialNumber, evt.Handle); } - [DllImport (Constants.ApplicationServicesCoreGraphicsLibrary)] unsafe extern static int /* CGError = int32_t */ CGGetEventTapList ( @@ -424,7 +410,7 @@ namespace CoreGraphics { CGEventTapInformation *tapList, out uint /* uint32_t* */ eventTapCount); - public unsafe CGEventTapInformation [] GetEventTapList () + public unsafe CGEventTapInformation []? GetEventTapList () { uint count; if (CGGetEventTapList (0, null, out count) != 0)