public override System.Drawing.Point PointToScreen(System.Drawing.Point point) { var r = Cocoa.SendRect(windowInfo.Handle, selConvertRectToScreen, Cocoa.SendRect(windowInfo.ViewHandle, selConvertRectFromBacking, new RectangleF(point.X, Height - point.Y, 0, 0))); return(new Point((int)r.X, (int)(GetCurrentScreenFrame().Height - r.Y))); }
private void ResetTrackingArea() { var owner = windowInfo.ViewHandle; if (trackingArea != IntPtr.Zero) { Cocoa.SendVoid(owner, selRemoveTrackingArea, trackingArea); Cocoa.SendVoid(trackingArea, Selector.Release); } var ownerBounds = Cocoa.SendRect(owner, selBounds); var options = (int)( NSTrackingAreaOptions.MouseEnteredAndExited | NSTrackingAreaOptions.ActiveInKeyWindow | NSTrackingAreaOptions.MouseMoved | NSTrackingAreaOptions.CursorUpdate); trackingArea = Cocoa.SendIntPtr(Cocoa.SendIntPtr(Class.Get("NSTrackingArea"), Selector.Alloc), selInitWithRect, ownerBounds, options, owner, IntPtr.Zero); Cocoa.SendVoid(owner, selAddTrackingArea, trackingArea); }
void ResetCursorRects(IntPtr sender, IntPtr cmd) { // We will add a new cursor rectangle that covers the complete view var rect = Cocoa.SendRect(windowInfo.ViewHandle, selBounds); // Inside this rectangle, the following NSCursor will be used var cursor = IntPtr.Zero; if (selectedCursor == MouseCursor.Default) { cursor = Cocoa.SendIntPtr(NSCursor, selArrowCursor); } else { cursor = ToNSCursor(selectedCursor); } // Setup the cursor rectangle if (cursor != IntPtr.Zero) { Cocoa.SendVoid(sender, selAddCursorRect, rect, cursor); } }
public override void ProcessEvents() { base.ProcessEvents(); while (true) { var e = Cocoa.SendIntPtr(NSApplication.Handle, selNextEventMatchingMask, uint.MaxValue, IntPtr.Zero, NSDefaultRunLoopMode, true); if (e == IntPtr.Zero) { break; } var type = (NSEventType)Cocoa.SendInt(e, selType); switch (type) { case NSEventType.KeyDown: { MacOSKeyCode keyCode = (MacOSKeyCode)Cocoa.SendUshort(e, selKeyCode); var isARepeat = Cocoa.SendBool(e, selIsARepeat); Key key = MacOSKeyMap.GetKey(keyCode); OnKeyDown(key, isARepeat); var s = Cocoa.FromNSString(Cocoa.SendIntPtr(e, selCharactersIgnoringModifiers)); foreach (var c in s) { int intVal = (int)c; if (!Char.IsControl(c) && (intVal < 63232 || intVal > 63235)) { // For some reason, arrow keys (mapped 63232-63235) // are seen as non-control characters, so get rid of those. OnKeyPress(c); } } } break; case NSEventType.KeyUp: { MacOSKeyCode keyCode = (MacOSKeyCode)Cocoa.SendUshort(e, selKeyCode); Key key = MacOSKeyMap.GetKey(keyCode); OnKeyUp(key); } break; case NSEventType.FlagsChanged: { var modifierFlags = (NSEventModifierMask)Cocoa.SendUint(e, selModifierFlags); UpdateModifierFlags(GetModifiers(modifierFlags)); } break; case NSEventType.MouseEntered: { var eventTrackingArea = Cocoa.SendIntPtr(e, selTrackingArea); var trackingAreaOwner = Cocoa.SendIntPtr(eventTrackingArea, selOwner); if (trackingAreaOwner == windowInfo.ViewHandle) { if (selectedCursor != MouseCursor.Default) { //SetCursor(selectedCursor); } OnMouseEnter(EventArgs.Empty); } } break; case NSEventType.MouseExited: { var eventTrackingArea = Cocoa.SendIntPtr(e, selTrackingArea); var trackingAreaOwner = Cocoa.SendIntPtr(eventTrackingArea, selOwner); if (trackingAreaOwner == windowInfo.ViewHandle) { if (selectedCursor != MouseCursor.Default) { //SetCursor(MouseCursor.Default); } OnMouseLeave(EventArgs.Empty); } } break; case NSEventType.LeftMouseDragged: case NSEventType.RightMouseDragged: case NSEventType.OtherMouseDragged: case NSEventType.MouseMoved: { Point p = new Point(MouseState.X, MouseState.Y); if (CursorVisible) { // Use absolute coordinates var pf = Cocoa.SendPoint(e, selLocationInWindowOwner); // Convert from points to pixel coordinates var rf = Cocoa.SendRect(windowInfo.Handle, selConvertRectToBacking, new RectangleF(pf.X, pf.Y, 0, 0)); // See CocoaDrawingGuide under "Converting from Window to View Coordinates" p = new Point( MathHelper.Clamp((int)Math.Round(rf.X), 0, Width), MathHelper.Clamp((int)Math.Round(Height - rf.Y), 0, Height)); } else { // Mouse has been disassociated, // use relative coordinates var dx = Cocoa.SendFloat(e, selDeltaX); var dy = Cocoa.SendFloat(e, selDeltaY); p = new Point( MathHelper.Clamp((int)Math.Round(p.X + dx), 0, Width), MathHelper.Clamp((int)Math.Round(p.Y + dy), 0, Height)); } // Only raise events when the mouse has actually moved if (MouseState.X != p.X || MouseState.Y != p.Y) { OnMouseMove(p.X, p.Y); } } break; case NSEventType.CursorUpdate: break; case NSEventType.ScrollWheel: { float dx, dy; if (Cocoa.SendBool(e, selHasPreciseScrollingDeltas)) { dx = Cocoa.SendFloat(e, selScrollingDeltaX) * MacOSFactory.ScrollFactor; dy = Cocoa.SendFloat(e, selScrollingDeltaY) * MacOSFactory.ScrollFactor; } else { dx = Cocoa.SendFloat(e, selDeltaX); dy = Cocoa.SendFloat(e, selDeltaY); } // Only raise wheel events when the user has actually scrolled if (dx != 0 || dy != 0) { OnMouseWheel(dx, dy); } } break; case NSEventType.LeftMouseDown: case NSEventType.RightMouseDown: case NSEventType.OtherMouseDown: { var buttonNumber = Cocoa.SendInt(e, selButtonNumber); OnMouseDown(GetMouseButton(buttonNumber)); } break; case NSEventType.LeftMouseUp: case NSEventType.RightMouseUp: case NSEventType.OtherMouseUp: { var buttonNumber = Cocoa.SendInt(e, selButtonNumber); OnMouseUp(GetMouseButton(buttonNumber)); } break; } Cocoa.SendVoid(NSApplication.Handle, selSendEvent, e); } // Handle closing if (shouldClose) { shouldClose = false; // PerformClose is equivalent to pressing the close-button, which // does not work in a borderless window. Handle this special case. if (GetStyleMask() == NSWindowStyle.Borderless) { if (WindowShouldClose(IntPtr.Zero, IntPtr.Zero, IntPtr.Zero)) { Cocoa.SendVoid(windowInfo.Handle, selClose); } } else { Cocoa.SendVoid(windowInfo.Handle, selPerformClose, windowInfo.Handle); } } }
private MouseCursor selectedCursor = MouseCursor.Default; // user-selected cursor public CocoaNativeWindow(int x, int y, int width, int height, string title, GraphicsMode mode, GameWindowFlags options, DisplayDevice device) { // Create the window class Interlocked.Increment(ref UniqueId); windowClass = Class.AllocateClass("OpenTK_GameWindow" + UniqueId, "NSWindow"); Class.RegisterMethod(windowClass, new WindowKeyDownDelegate(WindowKeyDown), "keyDown:", "v@:@"); Class.RegisterMethod(windowClass, new WindowDidResizeDelegate(WindowDidResize), "windowDidResize:", "v@:@"); Class.RegisterMethod(windowClass, new WindowDidMoveDelegate(WindowDidMove), "windowDidMove:", "v@:@"); Class.RegisterMethod(windowClass, new WindowDidBecomeKeyDelegate(WindowDidBecomeKey), "windowDidBecomeKey:", "v@:@"); Class.RegisterMethod(windowClass, new WindowDidResignKeyDelegate(WindowDidResignKey), "windowDidResignKey:", "v@:@"); Class.RegisterMethod(windowClass, new WindowWillMiniaturizeDelegate(WindowWillMiniaturize), "windowWillMiniaturize:", "v@:@"); Class.RegisterMethod(windowClass, new WindowDidMiniaturizeDelegate(WindowDidMiniaturize), "windowDidMiniaturize:", "v@:@"); Class.RegisterMethod(windowClass, new WindowDidDeminiaturizeDelegate(WindowDidDeminiaturize), "windowDidDeminiaturize:", "v@:@"); Class.RegisterMethod(windowClass, new WindowShouldZoomToFrameDelegate(WindowShouldZoomToFrame), "windowShouldZoom:toFrame:", "b@:@{NSRect={NSPoint=ff}{NSSize=ff}}"); Class.RegisterMethod(windowClass, new WindowShouldCloseDelegate(WindowShouldClose), "windowShouldClose:", "b@:@"); Class.RegisterMethod(windowClass, new AcceptsFirstResponderDelegate(AcceptsFirstResponder), "acceptsFirstResponder", "b@:"); Class.RegisterMethod(windowClass, new CanBecomeKeyWindowDelegate(CanBecomeKeyWindow), "canBecomeKeyWindow", "b@:"); Class.RegisterMethod(windowClass, new CanBecomeMainWindowDelegate(CanBecomeMainWindow), "canBecomeMainWindow", "b@:"); Class.RegisterClass(windowClass); IntPtr viewClass = Class.AllocateClass("OpenTK_NSView" + UniqueId, "NSView"); Class.RegisterMethod(viewClass, new ResetCursorRectsDelegate(ResetCursorRects), "resetCursorRects", "v@:"); Class.RegisterClass(viewClass); // Create window instance // Note: The coordinate system of Cocoa places (0,0) at the bottom left. // We need to get the height of the main screen and flip that in order // to place the window at the correct position. // Note: NSWindows are laid out relative to the main screen. var screenRect = Cocoa.SendRect( Cocoa.SendIntPtr( Cocoa.SendIntPtr(Class.Get("NSScreen"), Selector.Get("screens")), Selector.Get("objectAtIndex:"), 0), Selector.Get("frame")); var contentRect = new System.Drawing.RectangleF(x, screenRect.Height - height - y, width, height); var style = GetStyleMask(windowBorder); var bufferingType = NSBackingStore.Buffered; IntPtr windowPtr; windowPtr = Cocoa.SendIntPtr(windowClass, Selector.Alloc); windowPtr = Cocoa.SendIntPtr(windowPtr, Selector.Get("initWithContentRect:styleMask:backing:defer:"), contentRect, (int)style, (int)bufferingType, false); // Replace view with our custom implementation // that overrides resetCursorRects (maybe there is // a better way to implement this override?) // Existing view: IntPtr viewPtr = Cocoa.SendIntPtr(windowPtr, Selector.Get("contentView")); // Our custom view with the same bounds: viewPtr = Cocoa.SendIntPtr( Cocoa.SendIntPtr(viewClass, Selector.Alloc), Selector.Get("initWithFrame:"), Cocoa.SendRect(viewPtr, selBounds)); if (viewPtr != IntPtr.Zero) { Cocoa.SendVoid(windowPtr, Selector.Get("setContentView:"), viewPtr); } windowInfo = new CocoaWindowInfo(windowPtr); // Set up behavior Cocoa.SendIntPtr(windowPtr, Selector.Get("setDelegate:"), windowPtr); // The window class acts as its own delegate Cocoa.SendVoid(windowPtr, Selector.Get("makeKeyWindow")); SetTitle(title, false); ResetTrackingArea(); exists = true; NSApplication.Quit += ApplicationQuit; }
private RectangleF GetCurrentScreenVisibleFrame() { return(Cocoa.SendRect(GetCurrentScreen(), selVisibleFrame)); }
private RectangleF GetContentViewFrame() { return(Cocoa.SendRect(windowInfo.ViewHandle, selFrame)); }