//========================================================================
// GLFW 3.4 macOS – www.glfw.org
//————————————————————————
// Copyright (c) 2009-2019 Camilla Löwy
Copyright By PowCoder代写 加微信 powcoder
// This software is provided ‘as-is’, without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source
// distribution.
//========================================================================
// It is fine to use C99 in this file because it will not be built with VS
//========================================================================
#include “internal.h”
#include
#include
// Returns the style mask corresponding to the window settings
static NSUInteger getStyleMask(_GLFWwindow* window)
NSUInteger styleMask = NSWindowStyleMaskMiniaturizable;
if (window->monitor || !window->decorated)
styleMask |= NSWindowStyleMaskBorderless;
styleMask |= NSWindowStyleMaskTitled |
NSWindowStyleMaskClosable;
if (window->resizable)
styleMask |= NSWindowStyleMaskResizable;
return styleMask;
// Returns whether the cursor is in the content area of the specified window
static GLFWbool cursorInContentArea(_GLFWwindow* window)
const NSPoint pos = [window->ns.object mouseLocationOutsideOfEventStream];
return [window->ns.view mouse:pos inRect:[window->ns.view frame]];
// Hides the cursor if not already hidden
static void hideCursor(_GLFWwindow* window)
if (!_glfw.ns.cursorHidden)
[NSCursor hide];
_glfw.ns.cursorHidden = GLFW_TRUE;
// Shows the cursor if not already shown
static void showCursor(_GLFWwindow* window)
if (_glfw.ns.cursorHidden)
[NSCursor unhide];
_glfw.ns.cursorHidden = GLFW_FALSE;
// Updates the cursor image according to its cursor mode
static void updateCursorImage(_GLFWwindow* window)
if (window->cursorMode == GLFW_CURSOR_NORMAL)
showCursor(window);
if (window->cursor)
[(NSCursor*) window->cursor->ns.object set];
[[NSCursor arrowCursor] set];
hideCursor(window);
// Apply chosen cursor mode to a focused window
static void updateCursorMode(_GLFWwindow* window)
if (window->cursorMode == GLFW_CURSOR_DISABLED)
_glfw.ns.disabledCursorWindow = window;
_glfwGetCursorPosCocoa(window,
&_glfw.ns.restoreCursorPosX,
&_glfw.ns.restoreCursorPosY);
_glfwCenterCursorInContentArea(window);
CGAssociateMouseAndMouseCursorPosition(false);
else if (_glfw.ns.disabledCursorWindow == window)
_glfw.ns.disabledCursorWindow = NULL;
_glfwSetCursorPosCocoa(window,
_glfw.ns.restoreCursorPosX,
_glfw.ns.restoreCursorPosY);
// NOTE: The matching CGAssociateMouseAndMouseCursorPosition call is
// made in _glfwSetCursorPosCocoa as part of a workaround
if (cursorInContentArea(window))
updateCursorImage(window);
// Make the specified window and its video mode active on its monitor
static void acquireMonitor(_GLFWwindow* window)
_glfwSetVideoModeCocoa(window->monitor, &window->videoMode);
const CGRect bounds = CGDisplayBounds(window->monitor->ns.displayID);
const NSRect frame = NSMakeRect(bounds.origin.x,
_glfwTransformYCocoa(bounds.origin.y + bounds.size.height – 1),
bounds.size.width,
bounds.size.height);
[window->ns.object setFrame:frame display:YES];
_glfwInputMonitorWindow(window->monitor, window);
// Remove the window and restore the original video mode
static void releaseMonitor(_GLFWwindow* window)
if (window->monitor->window != window)
_glfwInputMonitorWindow(window->monitor, NULL);
_glfwRestoreVideoModeCocoa(window->monitor);
// Translates macOS key modifiers into GLFW ones
static int translateFlags(NSUInteger flags)
int mods = 0;
if (flags & NSEventModifierFlagShift)
mods |= GLFW_MOD_SHIFT;
if (flags & NSEventModifierFlagControl)
mods |= GLFW_MOD_CONTROL;
if (flags & NSEventModifierFlagOption)
mods |= GLFW_MOD_ALT;
if (flags & NSEventModifierFlagCommand)
mods |= GLFW_MOD_SUPER;
if (flags & NSEventModifierFlagCapsLock)
mods |= GLFW_MOD_CAPS_LOCK;
return mods;
// Translates a macOS keycode to a GLFW keycode
static int translateKey(unsigned int key)
if (key >= sizeof(_glfw.ns.keycodes) / sizeof(_glfw.ns.keycodes[0]))
return GLFW_KEY_UNKNOWN;
return _glfw.ns.keycodes[key];
// Translate a GLFW keycode to a Cocoa modifier flag
static NSUInteger translateKeyToModifierFlag(int key)
switch (key)
case GLFW_KEY_LEFT_SHIFT:
case GLFW_KEY_RIGHT_SHIFT:
return NSEventModifierFlagShift;
case GLFW_KEY_LEFT_CONTROL:
case GLFW_KEY_RIGHT_CONTROL:
return NSEventModifierFlagControl;
case GLFW_KEY_LEFT_ALT:
case GLFW_KEY_RIGHT_ALT:
return NSEventModifierFlagOption;
case GLFW_KEY_LEFT_SUPER:
case GLFW_KEY_RIGHT_SUPER:
return NSEventModifierFlagCommand;
case GLFW_KEY_CAPS_LOCK:
return NSEventModifierFlagCapsLock;
// Defines a constant for empty ranges in NSTextInputClient
static const NSRange kEmptyRange = { NSNotFound, 0 };
//————————————————————————
// Delegate for window related notifications
//————————————————————————
@interface GLFWWindowDelegate : NSObject
_GLFWwindow* window;
– (instancetype)initWithGlfwWindow:(_GLFWwindow *)initWindow;
@implementation GLFWWindowDelegate
– (instancetype)initWithGlfwWindow:(_GLFWwindow *)initWindow
self = [super init];
if (self != nil)
window = initWindow;
return self;
– (BOOL)windowShouldClose:(id)sender
_glfwInputWindowCloseRequest(window);
return NO;
– (void)windowDidResize:(NSNotification *)notification
if (window->context.source == GLFW_NATIVE_CONTEXT_API)
[window->context.nsgl.object update];
if (_glfw.ns.disabledCursorWindow == window)
_glfwCenterCursorInContentArea(window);
const int maximized = [window->ns.object isZoomed];
if (window->ns.maximized != maximized)
window->ns.maximized = maximized;
_glfwInputWindowMaximize(window, maximized);
const NSRect contentRect = [window->ns.view frame];
const NSRect fbRect = [window->ns.view convertRectToBacking:contentRect];
if (fbRect.size.width != window->ns.fbWidth ||
fbRect.size.height != window->ns.fbHeight)
window->ns.fbWidth = fbRect.size.width;
window->ns.fbHeight = fbRect.size.height;
_glfwInputFramebufferSize(window, fbRect.size.width, fbRect.size.height);
if (contentRect.size.width != window->ns.width ||
contentRect.size.height != window->ns.height)
window->ns.width = contentRect.size.width;
window->ns.height = contentRect.size.height;
_glfwInputWindowSize(window, contentRect.size.width, contentRect.size.height);
– (void)windowDidMove:(NSNotification *)notification
if (window->context.source == GLFW_NATIVE_CONTEXT_API)
[window->context.nsgl.object update];
if (_glfw.ns.disabledCursorWindow == window)
_glfwCenterCursorInContentArea(window);
_glfwGetWindowPosCocoa(window, &x, &y);
_glfwInputWindowPos(window, x, y);
– (void)windowDidMiniaturize:(NSNotification *)notification
if (window->monitor)
releaseMonitor(window);
_glfwInputWindowIconify(window, GLFW_TRUE);
– (void)windowDidDeminiaturize:(NSNotification *)notification
if (window->monitor)
acquireMonitor(window);
_glfwInputWindowIconify(window, GLFW_FALSE);
– (void)windowDidBecomeKey:(NSNotification *)notification
if (_glfw.ns.disabledCursorWindow == window)
_glfwCenterCursorInContentArea(window);
_glfwInputWindowFocus(window, GLFW_TRUE);
updateCursorMode(window);
– (void)windowDidResignKey:(NSNotification *)notification
if (window->monitor && window->autoIconify)
_glfwIconifyWindowCocoa(window);
_glfwInputWindowFocus(window, GLFW_FALSE);
– (void)windowDidChangeOcclusionState:(NSNotification* )notification
if ([window->ns.object occlusionState] & NSWindowOcclusionStateVisible)
window->ns.occluded = GLFW_FALSE;
window->ns.occluded = GLFW_TRUE;
//————————————————————————
// Content view class for the GLFW window
//————————————————————————
@interface GLFWContentView : NSView
_GLFWwindow* window;
NSTrackingArea* trackingArea;
NSMutableAttributedString* markedText;
– (instancetype)initWithGlfwWindow:(_GLFWwindow *)initWindow;
@implementation GLFWContentView
– (instancetype)initWithGlfwWindow:(_GLFWwindow *)initWindow
self = [super init];
if (self != nil)
window = initWindow;
trackingArea = nil;
markedText = [[NSMutableAttributedString alloc] init];
[self updateTrackingAreas];
// NOTE: kUTTypeURL corresponds to NSPasteboardTypeURL but is available
// on 10.7 without having been deprecated yet
[self NSString*) kUTTypeURL]];
return self;
– (void)dealloc
[trackingArea release];
[markedText release];
[super dealloc];
– (BOOL)isOpaque
return [window->ns.object isOpaque];
– (BOOL)canBecomeKeyView
return YES;
– (BOOL)acceptsFirstResponder
return YES;
– (BOOL)wantsUpdateLayer
return YES;
– (void)updateLayer
if (window->context.source == GLFW_NATIVE_CONTEXT_API)
[window->context.nsgl.object update];
_glfwInputWindowDamage(window);
– (void)cursorUpdate:(NSEvent *)event
updateCursorImage(window);
– (BOOL)acceptsFirstMouse:(NSEvent *)event
return YES;
– (void)mouseDown:(NSEvent *)event
_glfwInputMouseClick(window,
GLFW_MOUSE_BUTTON_LEFT,
GLFW_PRESS,
translateFlags([event modifierFlags]));
– (void)mouseDragged:(NSEvent *)event
[self mouseMoved:event];
– (void)mouseUp:(NSEvent *)event
_glfwInputMouseClick(window,
GLFW_MOUSE_BUTTON_LEFT,
GLFW_RELEASE,
translateFlags([event modifierFlags]));
– (void)mouseMoved:(NSEvent *)event
if (window->cursorMode == GLFW_CURSOR_DISABLED)
const double dx = [event deltaX] – window->ns.cursorWarpDeltaX;
const double dy = [event deltaY] – window->ns.cursorWarpDeltaY;
_glfwInputCursorPos(window,
window->virtualCursorPosX + dx,
window->virtualCursorPosY + dy);
const NSRect contentRect = [window->ns.view frame];
// NOTE: The returned location uses base 0,1 not 0,0
const NSPoint pos = [event locationInWindow];
_glfwInputCursorPos(window, pos.x, contentRect.size.height – pos.y);
window->ns.cursorWarpDeltaX = 0;
window->ns.cursorWarpDeltaY = 0;
– (void)rightMouseDown:(NSEvent *)event
_glfwInputMouseClick(window,
GLFW_MOUSE_BUTTON_RIGHT,
GLFW_PRESS,
translateFlags([event modifierFlags]));
– (void)rightMouseDragged:(NSEvent *)event
[self mouseMoved:event];
– (void)rightMouseUp:(NSEvent *)event
_glfwInputMouseClick(window,
GLFW_MOUSE_BUTTON_RIGHT,
GLFW_RELEASE,
translateFlags([event modifierFlags]));
– (void)otherMouseDown:(NSEvent *)event
_glfwInputMouseClick(window,
(int) [event buttonNumber],
GLFW_PRESS,
translateFlags([event modifierFlags]));
– (void)otherMouseDragged:(NSEvent *)event
[self mouseMoved:event];
– (void)otherMouseUp:(NSEvent *)event
_glfwInputMouseClick(window,
(int) [event buttonNumber],
GLFW_RELEASE,
translateFlags([event modifierFlags]));
– (void)mouseExited:(NSEvent *)event
if (window->cursorMode == GLFW_CURSOR_HIDDEN)
showCursor(window);
_glfwInputCursorEnter(window, GLFW_FALSE);
– (void)mouseEntered:(NSEvent *)event
if (window->cursorMode == GLFW_CURSOR_HIDDEN)
hideCursor(window);
_glfwInputCursorEnter(window, GLFW_TRUE);
– (void)viewDidChangeBackingProperties
const NSRect contentRect = [window->ns.view frame];
const NSRect fbRect = [window->ns.view convertRectToBacking:contentRect];
const float xscale = fbRect.size.width / contentRect.size.width;
const float yscale = fbRect.size.height / contentRect.size.height;
if (xscale != window->ns.xscale || yscale != window->ns.yscale)
if (window->ns.retina && window->ns.layer)
[window->ns.layer setContentsScale:[window->ns.object backingScaleFactor]];
window->ns.xscale = xscale;
window->ns.yscale = yscale;
_glfwInputWindowContentScale(window, xscale, yscale);
if (fbRect.size.width != window->ns.fbWidth ||
fbRect.size.height != window->ns.fbHeight)
window->ns.fbWidth = fbRect.size.width;
window->ns.fbHeight = fbRect.size.height;
_glfwInputFramebufferSize(window, fbRect.size.width, fbRect.size.height);
– (void)drawRect:(NSRect)rect
_glfwInputWindowDamage(window);
– (void)updateTrackingAreas
if (trackingArea != nil)
[self removeTrackingArea:trackingArea];
[trackingArea release];
const NSTrackingAreaOptions options = NSTrackingMouseEnteredAndExited |
NSTrackingActiveInKeyWindow |
NSTrackingEnabledDuringMouseDrag |
NSTrackingCursorUpdate |
NSTrackingInVisibleRect |
NSTrackingAssumeInside;
trackingArea = [[NSTrackingArea alloc] initWithRect:[self bounds]
options:options
owner:self
userInfo:nil];
[self addTrackingArea:trackingArea];
[super updateTrackingAreas];
– (void)keyDown:(NSEvent *)event
const int key = translateKey([event keyCode]);
const int mods = translateFlags([event modifierFlags]);
_glfwInputKey(window, key, [event keyCode], GLFW_PRESS, mods);
– (void)flagsChanged:(NSEvent *)event
int action;
const unsigned int modifierFlags =
[event modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask;
const int key = translateKey([event keyCode]);
const int mods = translateFlags(modifierFlags);
const NSUInteger keyFlag = translateKeyToModifierFlag(key);
if (keyFlag & modifierFlags)
if (window->keys[key] == GLFW_PRESS)
action = GLFW_RELEASE;
action = GLFW_PRESS;
action = GLFW_RELEASE;
_glfwInputKey(window, key, [event keyCode], action, mods);
– (void)keyUp:(NSEvent *)event
const int key = translateKey([event keyCode]);
const int mods = translateFlags([event modifierFlags]);
_glfwInputKey(window, key, [event keyCode], GLFW_RELEASE, mods);
– (void)scrollWheel:(NSEvent *)event
double deltaX = [event scrollingDeltaX];
double deltaY = [event scrollingDeltaY];
if ([event hasPreciseScrollingDeltas])
deltaX *= 0.1;
deltaY *= 0.1;
if (fabs(deltaX) > 0.0 || fabs(deltaY) > 0.0)
_glfwInputScroll(window, deltaX, deltaY);
– (NSDragOperation)draggingEntered:(id
// HACK: We don’t know what to say here because we don’t know what the
// application wants to do with the paths
return NSDragOperationGeneric;
– (BOOL)performDragOperation:(id
const NSRect contentRect = [window->ns.view frame];
// NOTE: The returned location uses base 0,1 not 0,0
const NSPoint pos = [sender draggingLocation];
_glfwInputCursorPos(window, pos.x, contentRect.size.height – pos.y);
NSPasteboard* pasteboard = [sender draggingPasteboard];
NSDictionary* options =
NSArray* urls = [pasteboard class]]
options:options];
const NSUInteger count = [urls count];
if (count)
char** paths = _glfw_calloc(count, sizeof(char*));
for (NSUInteger i = 0; i < count; i++) paths[i] = _glfw_strdup([urls[i] fileSystemRepresentation]); _glfwInputDrop(window, (int) count, (const char**) paths); for (NSUInteger i = 0; i < count; i++) _glfw_free(paths[i]); _glfw_free(paths); return YES; - (BOOL)hasMarkedText return [markedText length] > 0;
– (NSRange)markedRange
if ([markedText length] > 0)
return NSMakeRange(0, [markedText length] – 1);
return kEmptyRange;
– (NSRange)selectedRange
return kEmptyRange;
– (void)setMarkedText:(id)string
selectedRange:(NSRange)selectedRange
replacementRange:(NSRange)replacementRange
[markedText release];
if ([string isKindOfClass:[NSAttributedString class]])
markedText = [[NSMutableAttributedString alloc] initWithAttributedString:string];
markedText = [[NSMutableAttributedString alloc] initWithString:string];
– (void)unmarkText
[[markedText mutableString]
– (NSArray*)validAttributesForMarkedText
return [NSArray array];
– (NSAttributedString*)attributedSubstringForProposedRange:(NSRange)range
actualRange:(NSRangePointer)actualRange
return nil;
– (NSUInteger)characterIndexForPoint:(NSPoint)point
– (NSRect)firstRectForCharacterRange:(NSRange)range
actualRange:(NSRangePointer)actualRange
const NSRect frame = [window->ns.view frame];
return NSMakeRect(frame.origin.x, frame.origin.y, 0.0, 0.0);
– (void)insertText:(id)string replacementRange:(NSRange)replacementRange
NSString* characters;
NSEvent* event = [NSApp currentEvent];
const int mods = translateFlags([event modifierFlags]);
const int plain = !(mods & GLFW_MOD_SUPER);
程序代写 CS代考 加微信: powcoder QQ: 1823890830 Email: powcoder@163.com