[Mac] Implemented Mouse.GetCursorState()

This commit is contained in:
thefiddler 2014-05-10 17:54:34 +02:00
parent b89c920f32
commit 96aaef9b37
8 changed files with 355 additions and 45 deletions

View file

@ -2,7 +2,7 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
<PropertyGroup>
<ProjectType>Local</ProjectType>
<ProductVersion>8.0.50727</ProductVersion>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{A37A7E14-0000-0000-0000-000000000000}</ProjectGuid>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@ -783,21 +783,22 @@
<Compile Include="Platform\MacOS\Carbon\CarbonAPI.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Platform\MacOS\Carbon\QuartzDisplayServicesAPI.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Platform\MacOS\Carbon\MacOSKeys.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Platform\MacOS\Carbon\CoreFoundation.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Platform\MacOS\Carbon\Cgl.cs" />
<Compile Include="WindowIcon.cs" />
<Compile Include="Platform\MacOS\Cocoa\NSBitmapFormat.cs" />
<Compile Include="Platform\NativeWindowBase.cs" />
<Compile Include="Input\MouseScrollWheel.cs" />
<Compile Include="Input\MouseEventArgs.cs" />
<Compile Include="Platform\MacOS\Quartz\EventServices.cs" />
<Compile Include="Platform\MacOS\Quartz\DisplayServices.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Platform\MacOS\Quartz\CoreFoundation.cs">
<SubType>Code</SubType>
</Compile>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
@ -827,4 +828,7 @@
</Properties>
</MonoDevelop>
</ProjectExtensions>
<ItemGroup>
<Folder Include="Platform\MacOS\Quartz\" />
</ItemGroup>
</Project>

View file

@ -89,7 +89,7 @@ namespace OpenTK.Platform.MacOS
// Initialize and register the settings dictionary
settings =
Cocoa.SendIntPtr(settings, Selector.Get("initWithObjectsAndKeys:"),
momentum_scrolling, Cocoa.ToNSString("AppleMomentumScrollSupported"),
//momentum_scrolling, Cocoa.ToNSString("AppleMomentumScrollSupported"),
press_and_hold, Cocoa.ToNSString("ApplePressAndHoldEnabled"),
IntPtr.Zero);
Cocoa.SendVoid(

View file

@ -144,9 +144,6 @@ namespace OpenTK.Platform.MacOS
private bool cursorInsideWindow = true;
private MouseCursor selectedCursor = MouseCursor.Default; // user-selected cursor
private const float scrollFactor = 10.0f;
private const bool exclusiveFullscreen = false;
public CocoaNativeWindow(int x, int y, int width, int height, string title, GraphicsMode mode, GameWindowFlags options, DisplayDevice device)
{
// Create the window class
@ -527,8 +524,8 @@ namespace OpenTK.Platform.MacOS
float dx, dy;
if (Cocoa.SendBool(e, selHasPreciseScrollingDeltas))
{
dx = Cocoa.SendFloat(e, selScrollingDeltaX) / scrollFactor;
dy = Cocoa.SendFloat(e, selScrollingDeltaY) / scrollFactor;
dx = Cocoa.SendFloat(e, selScrollingDeltaX) * MacOSFactory.ScrollFactor;
dy = Cocoa.SendFloat(e, selScrollingDeltaY) * MacOSFactory.ScrollFactor;
}
else
{
@ -675,9 +672,9 @@ namespace OpenTK.Platform.MacOS
if (windowState == WindowState.Fullscreen)
{
SetMenuVisible(true);
if (exclusiveFullscreen)
if (MacOSFactory.ExclusiveFullscreen)
{
OpenTK.Platform.MacOS.Carbon.CG.DisplayReleaseAll();
CG.DisplayReleaseAll();
Cocoa.SendVoid(windowInfo.Handle, selSetLevel, normalLevel);
}
@ -736,12 +733,12 @@ namespace OpenTK.Platform.MacOS
if (value == WindowState.Fullscreen)
{
if (exclusiveFullscreen)
if (MacOSFactory.ExclusiveFullscreen)
{
normalLevel = Cocoa.SendInt(windowInfo.Handle, selLevel);
var windowLevel = OpenTK.Platform.MacOS.Carbon.CG.ShieldingWindowLevel();
var windowLevel = CG.ShieldingWindowLevel();
OpenTK.Platform.MacOS.Carbon.CG.CaptureAllDisplays();
CG.CaptureAllDisplays();
Cocoa.SendVoid(windowInfo.Handle, selSetLevel, windowLevel);
}
@ -1074,7 +1071,7 @@ namespace OpenTK.Platform.MacOS
Mouse.SetPosition((int)p.X, (int)p.Y);
}
Carbon.CG.AssociateMouseAndMouseCursorPosition(visible);
CG.AssociateMouseAndMouseCursorPosition(visible);
Cocoa.SendVoid(NSCursor, visible ? selUnhide : selHide);
}

View file

@ -100,6 +100,10 @@ namespace OpenTK.Platform.MacOS
readonly MappedGamePadDriver mapped_gamepad = new MappedGamePadDriver();
IntPtr MouseEventTap;
IntPtr MouseEventTapSource;
MouseState CursorState;
NativeMethods.IOHIDDeviceCallback HandleDeviceAdded;
NativeMethods.IOHIDDeviceCallback HandleDeviceRemoved;
NativeMethods.IOHIDValueCallback HandleDeviceValueReceived;
@ -118,14 +122,93 @@ namespace OpenTK.Platform.MacOS
HandleDeviceRemoved = DeviceRemoved;
HandleDeviceValueReceived = DeviceValueReceived;
// For retrieving input directly from the hardware
hidmanager = CreateHIDManager();
RegisterHIDCallbacks(hidmanager);
// For retrieving the global cursor position
RegisterMouseMonitor();
}
#endregion
#region Private Members
void RegisterMouseMonitor()
{
Debug.Write("Creating mouse event monitor... ");
MouseEventTapDelegate = MouseEventTapCallback;
MouseEventTap = CG.EventTapCreate(
CGEventTapLocation.HIDEventTap,
CGEventTapPlacement.HeadInsert,
CGEventTapOptions.ListenOnly,
CGEventMask.AllMouse,
MouseEventTapDelegate,
IntPtr.Zero);
if (MouseEventTap != IntPtr.Zero)
{
MouseEventTapSource = CF.MachPortCreateRunLoopSource(IntPtr.Zero, MouseEventTap, IntPtr.Zero);
CF.RunLoopAddSource(RunLoop, MouseEventTapSource, CF.RunLoopModeDefault);
}
Debug.WriteLine(
MouseEventTap != IntPtr.Zero && MouseEventTapSource != IntPtr.Zero ?
"success!" : "failed.");
}
CG.EventTapCallBack MouseEventTapDelegate;
IntPtr MouseEventTapCallback(
IntPtr proxy,
CGEventType type,
IntPtr @event,
IntPtr refcon)
{
CursorState.SetIsConnected(true);
switch (type)
{
case CGEventType.MouseMoved:
case CGEventType.LeftMouseDragged:
case CGEventType.RightMouseDragged:
case CGEventType.OtherMouseDragged:
{
Carbon.HIPoint p = CG.EventGetLocation(@event);
CursorState.X = (int)Math.Round(p.X);
CursorState.Y = (int)Math.Round(p.Y);
}
break;
case CGEventType.ScrollWheel:
CursorState.SetScrollRelative(
(float)CG.EventGetDoubleValueField(@event, CGEventField.ScrollWheelEventPointDeltaAxis2) * MacOSFactory.ScrollFactor,
(float)CG.EventGetDoubleValueField(@event, CGEventField.ScrollWheelEventPointDeltaAxis1) * MacOSFactory.ScrollFactor);
break;
case CGEventType.LeftMouseDown:
case CGEventType.RightMouseDown:
case CGEventType.OtherMouseDown:
{
int n = CG.EventGetIntegerValueField(@event, CGEventField.MouseEventButtonNumber);
MouseButton b = MouseButton.Left + n;
CursorState[b] = true;
}
break;
case CGEventType.LeftMouseUp:
case CGEventType.RightMouseUp:
case CGEventType.OtherMouseUp:
{
int n = CG.EventGetIntegerValueField(@event, CGEventField.MouseEventButtonNumber);
MouseButton b = MouseButton.Left + n;
CursorState[b] = false;
}
break;
}
return @event;
}
IOHIDManagerRef CreateHIDManager()
{
return NativeMethods.IOHIDManagerCreate(IntPtr.Zero, IntPtr.Zero);
@ -836,10 +919,7 @@ namespace OpenTK.Platform.MacOS
MouseState IMouseDriver2.GetCursorState()
{
var state = new MouseState();
state.SetIsConnected(true);
return state;
return CursorState;
}
void IMouseDriver2.SetPosition(double x, double y)
@ -1658,6 +1738,17 @@ namespace OpenTK.Platform.MacOS
HandleDeviceAdded = null;
HandleDeviceRemoved = null;
HandleDeviceValueReceived = null;
if (MouseEventTap != IntPtr.Zero)
{
CF.CFRelease(MouseEventTap);
MouseEventTap = IntPtr.Zero;
}
if (MouseEventTapSource != IntPtr.Zero)
{
CF.CFRelease(MouseEventTapSource);
MouseEventTapSource = IntPtr.Zero;
}
}
else
{

View file

@ -37,6 +37,9 @@ namespace OpenTK.Platform.MacOS
class MacOSFactory : PlatformFactoryBase
{
internal const float ScrollFactor = 0.1f;
internal static bool ExclusiveFullscreen = false;
readonly IInputDriver2 InputDriver = new HIDInput();
#region IPlatformFactory Members

View file

@ -32,10 +32,14 @@ using System.Text;
namespace OpenTK.Platform.MacOS.Carbon
{
using CFAllocatorRef = IntPtr;
using CFIndex = System.IntPtr;
using CFRunLoop = System.IntPtr;
using CFRunLoopRef = IntPtr;
using CFRunLoopSourceRef = IntPtr;
using CFStringRef = System.IntPtr;
using CFTypeRef = System.IntPtr;
using CFMachPortRef = IntPtr;
struct CFArray
{
@ -214,5 +218,17 @@ namespace OpenTK.Platform.MacOS.Carbon
[DllImport(appServices)]
internal static extern CFRunLoopExitReason CFRunLoopRunInMode(
IntPtr cfstrMode, double interval, bool returnAfterSourceHandled);
[DllImport(appServices, EntryPoint = "CFMachPortCreateRunLoopSource")]
internal static extern CFRunLoopSourceRef MachPortCreateRunLoopSource(
CFAllocatorRef allocator,
CFMachPortRef port,
CFIndex order);
[DllImport(appServices, EntryPoint = "CFRunLoopAddSource")]
internal static extern void RunLoopAddSource(
CFRunLoopRef rl,
CFRunLoopSourceRef source,
CFStringRef mode);
}
}

View file

@ -28,8 +28,9 @@
using System;
using System.Runtime.InteropServices;
using System.Diagnostics;
using OpenTK.Platform.MacOS.Carbon;
namespace OpenTK.Platform.MacOS.Carbon
namespace OpenTK.Platform.MacOS
{
using CGDirectDisplayID = System.IntPtr;
@ -55,18 +56,18 @@ namespace OpenTK.Platform.MacOS.Carbon
NoneAvailable = 1011,
}
internal static class CG
partial class CG
{
const string appServices = "/System/Library/Frameworks/ApplicationServices.framework/Versions/Current/ApplicationServices";
const string lib = "/System/Library/Frameworks/ApplicationServices.framework/Versions/Current/ApplicationServices";
// CGPoint -> HIPoint
// CGSize -> HISize
// CGRect -> HIRect
[DllImport(appServices,EntryPoint="CGGetActiveDisplayList")]
[DllImport(lib,EntryPoint="CGGetActiveDisplayList")]
internal unsafe static extern CGDisplayErr GetActiveDisplayList(int maxDisplays, IntPtr* activeDspys, out int dspyCnt);
[DllImport(appServices,EntryPoint="CGMainDisplayID")]
[DllImport(lib,EntryPoint="CGMainDisplayID")]
internal static extern IntPtr MainDisplayID();
// Note: sizeof(HIRect) == 16, which is larger than 8 bytes.
@ -81,55 +82,55 @@ namespace OpenTK.Platform.MacOS.Carbon
return rect;
}
[DllImport(appServices, EntryPoint = "CGDisplayBounds")]
[DllImport(lib, EntryPoint = "CGDisplayBounds")]
unsafe static extern void DisplayBounds(out HIRect rect, IntPtr display);
[DllImport(appServices,EntryPoint="CGDisplayPixelsWide")]
[DllImport(lib,EntryPoint="CGDisplayPixelsWide")]
internal static extern int DisplayPixelsWide(IntPtr display);
[DllImport(appServices,EntryPoint="CGDisplayPixelsHigh")]
[DllImport(lib,EntryPoint="CGDisplayPixelsHigh")]
internal static extern int DisplayPixelsHigh(IntPtr display);
[DllImport(appServices,EntryPoint="CGDisplayCurrentMode")]
[DllImport(lib,EntryPoint="CGDisplayCurrentMode")]
internal static extern IntPtr DisplayCurrentMode(IntPtr display);
[DllImport(appServices,EntryPoint="CGDisplayCapture")]
[DllImport(lib,EntryPoint="CGDisplayCapture")]
internal static extern CGDisplayErr DisplayCapture(IntPtr display);
[DllImport(appServices,EntryPoint="CGCaptureAllDisplays")]
[DllImport(lib,EntryPoint="CGCaptureAllDisplays")]
internal static extern CGDisplayErr CaptureAllDisplays();
[DllImport(appServices,EntryPoint="CGShieldingWindowLevel")]
[DllImport(lib,EntryPoint="CGShieldingWindowLevel")]
internal static extern uint ShieldingWindowLevel();
[DllImport(appServices,EntryPoint="CGDisplayRelease")]
[DllImport(lib,EntryPoint="CGDisplayRelease")]
internal static extern CGDisplayErr DisplayRelease(IntPtr display);
[DllImport(appServices,EntryPoint="CGReleaseAllDisplays")]
[DllImport(lib,EntryPoint="CGReleaseAllDisplays")]
internal static extern CGDisplayErr DisplayReleaseAll();
[DllImport(appServices, EntryPoint = "CGDisplayAvailableModes")]
[DllImport(lib, EntryPoint = "CGDisplayAvailableModes")]
internal static extern IntPtr DisplayAvailableModes(IntPtr display);
[DllImport(appServices, EntryPoint = "CGDisplaySwitchToMode")]
[DllImport(lib, EntryPoint = "CGDisplaySwitchToMode")]
internal static extern IntPtr DisplaySwitchToMode(IntPtr display, IntPtr displayMode);
[DllImport(appServices, EntryPoint = "CGWarpMouseCursorPosition")]
[DllImport(lib, EntryPoint = "CGWarpMouseCursorPosition")]
internal static extern CGError WarpMouseCursorPosition(HIPoint newCursorPosition);
[DllImport(appServices, EntryPoint = "CGCursorIsVisible")]
[DllImport(lib, EntryPoint = "CGCursorIsVisible")]
internal static extern bool CursorIsVisible();
[DllImport(appServices, EntryPoint = "CGDisplayShowCursor")]
[DllImport(lib, EntryPoint = "CGDisplayShowCursor")]
internal static extern CGError DisplayShowCursor(CGDirectDisplayID display);
[DllImport(appServices, EntryPoint = "CGDisplayHideCursor")]
[DllImport(lib, EntryPoint = "CGDisplayHideCursor")]
internal static extern CGError DisplayHideCursor(CGDirectDisplayID display);
[DllImport(appServices, EntryPoint = "CGAssociateMouseAndMouseCursorPosition")]
[DllImport(lib, EntryPoint = "CGAssociateMouseAndMouseCursorPosition")]
internal static extern CGError AssociateMouseAndMouseCursorPosition(bool connected);
[DllImport(appServices, EntryPoint="CGSetLocalEventsSuppressionInterval")]
[DllImport(lib, EntryPoint="CGSetLocalEventsSuppressionInterval")]
internal static extern CGError SetLocalEventsSuppressionInterval(double seconds);
}
}

View file

@ -0,0 +1,198 @@
#region License
//
// EventServices.cs
//
// Author:
// Stefanos A. <stapostol@gmail.com>
//
// Copyright (c) 2006-2014 Stefanos Apostolopoulos
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#endregion
using System;
using System.Runtime.InteropServices;
namespace OpenTK.Platform.MacOS
{
using CGEventTapProxy = IntPtr;
using CGEventRef = IntPtr;
using CFMachPortRef = IntPtr;
partial class CG
{
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate CGEventRef EventTapCallBack(
CGEventTapProxy proxy,
CGEventType type,
CGEventRef @event,
IntPtr refcon);
[DllImport(lib, EntryPoint = "CGEventTapCreate")]
public static extern CFMachPortRef EventTapCreate(
CGEventTapLocation tap,
CGEventTapPlacement place,
CGEventTapOptions options,
CGEventMask eventsOfInterest,
[MarshalAs(UnmanagedType.FunctionPtr)]
EventTapCallBack callback,
IntPtr refcon);
[DllImport(lib, EntryPoint = "CGEventGetDoubleValueField")]
internal static extern double EventGetDoubleValueField(
CGEventRef @event,
CGEventField field);
[DllImport(lib, EntryPoint = "CGEventGetIntegerValueField")]
internal static extern int EventGetIntegerValueField(
CGEventRef @event,
CGEventField field);
[DllImport(lib, EntryPoint = "CGEventGetLocation")]
internal static extern Carbon.HIPoint EventGetLocation(CGEventRef @event);
}
enum CGEventTapLocation
{
HIDEventTap = 0,
SessionEventTap,
AnnotatedSessionEventTap
}
enum CGEventTapPlacement
{
HeadInsert = 0,
TailAppend
}
enum CGEventTapOptions
{
Default = 0x00000000,
ListenOnly = 0x00000001
}
[Flags]
enum CGEventMask : long
{
LeftMouseDown = 1 << CGEventType.LeftMouseDown,
LeftMouseUp = 1 << CGEventType.LeftMouseUp,
RightMouseDown = 1 << CGEventType.RightMouseDown,
RightMouseUp = 1 << CGEventType.RightMouseUp,
MouseMoved = 1 << CGEventType.MouseMoved,
LeftMouseDragged = 1 << CGEventType.LeftMouseDown,
RightMouseDragged = 1 << CGEventType.RightMouseDown,
KeyDown = 1 << CGEventType.KeyDown,
KeyUp = 1 << CGEventType.KeyUp,
FlagsChanged = 1 << CGEventType.FlagsChanged,
ScrollWheel = 1 << CGEventType.ScrollWheel,
TabletPointer = 1 << CGEventType.TabletPointer,
TabletProximity = 1 << CGEventType.TabletProximity,
OtherMouseDown = 1 << CGEventType.OtherMouseDown,
OtherMouseUp = 1 << CGEventType.OtherMouseUp,
OtherMouseDragged = 1 << CGEventType.OtherMouseDragged,
All = -1,
AllMouse =
LeftMouseDown | LeftMouseUp | LeftMouseDragged |
RightMouseDown | RightMouseUp | RightMouseDragged |
OtherMouseDown | OtherMouseUp | OtherMouseDragged |
ScrollWheel | MouseMoved
}
enum CGEventType
{
Null = 0,
LeftMouseDown = 1,
LeftMouseUp = 2,
RightMouseDown = 3,
RightMouseUp = 4,
MouseMoved = 5,
LeftMouseDragged = 6,
RightMouseDragged = 7,
KeyDown = 10,
KeyUp = 11,
FlagsChanged = 12,
ScrollWheel = 22,
TabletPointer = 23,
TabletProximity = 24,
OtherMouseDown = 25,
OtherMouseUp = 26,
OtherMouseDragged = 27,
TapDisabledByTimeout = -2,
TapDisabledByUserInput = -1
}
enum CGEventField
{
MouseEventNumber = 0,
MouseEventClickState = 1,
MouseEventPressure = 2,
MouseEventButtonNumber = 3,
MouseEventDeltaX = 4,
MouseEventDeltaY = 5,
MouseEventInstantMouser = 6,
MouseEventSubtype = 7,
KeyboardEventAutorepeat = 8,
KeyboardEventKeycode = 9,
KeyboardEventKeyboardType = 10,
ScrollWheelEventDeltaAxis1 = 11,
ScrollWheelEventDeltaAxis2 = 12,
ScrollWheelEventDeltaAxis3 = 13,
ScrollWheelEventFixedPtDeltaAxis1 = 93,
ScrollWheelEventFixedPtDeltaAxis2 = 94,
ScrollWheelEventFixedPtDeltaAxis3 = 95,
ScrollWheelEventPointDeltaAxis1 = 96,
ScrollWheelEventPointDeltaAxis2 = 97,
ScrollWheelEventPointDeltaAxis3 = 98,
ScrollWheelEventInstantMouser = 14,
TabletEventPointX = 15,
TabletEventPointY = 16,
TabletEventPointZ = 17,
TabletEventPointButtons = 18,
TabletEventPointPressure = 19,
TabletEventTiltX = 20,
TabletEventTiltY = 21,
TabletEventRotation = 22,
TabletEventTangentialPressure = 23,
TabletEventDeviceID = 24,
TabletEventVendor1 = 25,
TabletEventVendor2 = 26,
TabletEventVendor3 = 27,
TabletProximityEventVendorID = 28,
TabletProximityEventTabletID = 29,
TabletProximityEventPointerID = 30,
TabletProximityEventDeviceID = 31,
TabletProximityEventSystemTabletID = 32,
TabletProximityEventVendorPointerType = 33,
TabletProximityEventVendorPointerSerialNumber = 34,
TabletProximityEventVendorUniqueID = 35,
TabletProximityEventCapabilityMask = 36,
TabletProximityEventPointerType = 37,
TabletProximityEventEnterProximity = 38,
EventTargetProcessSerialNumber = 39,
EventTargetUnixProcessID = 40,
EventSourceUnixProcessID = 41,
EventSourceUserData = 42,
EventSourceUserID = 43,
EventSourceGroupID = 44,
EventSourceStateID = 45,
ScrollWheelEventIsContinuous = 88
}
}