forked from sascha/godot
[macOS] Cleanup and split Objective-C objects to the separate files
parent
33d6d4bdf7
commit
b84ef16aa7
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,42 @@
|
||||
/*************************************************************************/
|
||||
/* godot_application.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef GODOT_APPLICATION_H
|
||||
#define GODOT_APPLICATION_H
|
||||
|
||||
#include "core/os/os.h"
|
||||
|
||||
#import <AppKit/AppKit.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface GodotApplication : NSApplication
|
||||
@end
|
||||
|
||||
#endif // GODOT_APPLICATION_H
|
||||
@ -0,0 +1,53 @@
|
||||
/*************************************************************************/
|
||||
/* godot_application.mm */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "godot_application.h"
|
||||
|
||||
#include "display_server_osx.h"
|
||||
|
||||
@implementation GodotApplication
|
||||
|
||||
- (void)sendEvent:(NSEvent *)event {
|
||||
DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton();
|
||||
if (ds) {
|
||||
ds->send_event(event);
|
||||
}
|
||||
|
||||
// From http://cocoadev.com/index.pl?GameKeyboardHandlingAlmost
|
||||
// This works around an AppKit bug, where key up events while holding
|
||||
// down the command key don't get sent to the key window.
|
||||
if ([event type] == NSEventTypeKeyUp && ([event modifierFlags] & NSEventModifierFlagCommand)) {
|
||||
[[self keyWindow] sendEvent:event];
|
||||
} else {
|
||||
[super sendEvent:event];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@ -0,0 +1,45 @@
|
||||
/*************************************************************************/
|
||||
/* godot_application_delegate.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef GODOT_APPLICATION_DELEGATE_H
|
||||
#define GODOT_APPLICATION_DELEGATE_H
|
||||
|
||||
#include "core/os/os.h"
|
||||
|
||||
#import <AppKit/AppKit.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface GodotApplicationDelegate : NSObject
|
||||
- (void)forceUnbundledWindowActivationHackStep1;
|
||||
- (void)forceUnbundledWindowActivationHackStep2;
|
||||
- (void)forceUnbundledWindowActivationHackStep3;
|
||||
@end
|
||||
|
||||
#endif // GODOT_APPLICATION_DELEGATE_H
|
||||
@ -0,0 +1,132 @@
|
||||
/*************************************************************************/
|
||||
/* godot_application_delegate.mm */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "godot_application_delegate.h"
|
||||
|
||||
#include "display_server_osx.h"
|
||||
#include "os_osx.h"
|
||||
|
||||
@implementation GodotApplicationDelegate
|
||||
|
||||
- (void)forceUnbundledWindowActivationHackStep1 {
|
||||
// Step 1: Switch focus to macOS SystemUIServer process.
|
||||
// Required to perform step 2, TransformProcessType will fail if app is already the in focus.
|
||||
for (NSRunningApplication *app in [NSRunningApplication runningApplicationsWithBundleIdentifier:@"com.apple.systemuiserver"]) {
|
||||
[app activateWithOptions:NSApplicationActivateIgnoringOtherApps];
|
||||
break;
|
||||
}
|
||||
[self performSelector:@selector(forceUnbundledWindowActivationHackStep2)
|
||||
withObject:nil
|
||||
afterDelay:0.02];
|
||||
}
|
||||
|
||||
- (void)forceUnbundledWindowActivationHackStep2 {
|
||||
// Step 2: Register app as foreground process.
|
||||
ProcessSerialNumber psn = { 0, kCurrentProcess };
|
||||
(void)TransformProcessType(&psn, kProcessTransformToForegroundApplication);
|
||||
[self performSelector:@selector(forceUnbundledWindowActivationHackStep3) withObject:nil afterDelay:0.02];
|
||||
}
|
||||
|
||||
- (void)forceUnbundledWindowActivationHackStep3 {
|
||||
// Step 3: Switch focus back to app window.
|
||||
[[NSRunningApplication currentApplication] activateWithOptions:NSApplicationActivateIgnoringOtherApps];
|
||||
}
|
||||
|
||||
- (void)applicationDidFinishLaunching:(NSNotification *)notice {
|
||||
NSString *nsappname = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"];
|
||||
if (nsappname == nil || isatty(STDOUT_FILENO) || isatty(STDIN_FILENO) || isatty(STDERR_FILENO)) {
|
||||
// If the executable is started from terminal or is not bundled, macOS WindowServer won't register and activate app window correctly (menu and title bar are grayed out and input ignored).
|
||||
[self performSelector:@selector(forceUnbundledWindowActivationHackStep1) withObject:nil afterDelay:0.02];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)applicationDidResignActive:(NSNotification *)notification {
|
||||
if (OS::get_singleton()->get_main_loop()) {
|
||||
OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_FOCUS_OUT);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)applicationDidBecomeActive:(NSNotification *)notification {
|
||||
if (OS::get_singleton()->get_main_loop()) {
|
||||
OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_FOCUS_IN);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)globalMenuCallback:(id)sender {
|
||||
DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton();
|
||||
if (ds) {
|
||||
return ds->menu_callback(sender);
|
||||
}
|
||||
}
|
||||
|
||||
- (NSMenu *)applicationDockMenu:(NSApplication *)sender {
|
||||
DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton();
|
||||
if (ds) {
|
||||
return ds->get_dock_menu();
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)application:(NSApplication *)sender openFile:(NSString *)filename {
|
||||
// Note: may be called called before main loop init!
|
||||
OS_OSX *os = (OS_OSX *)OS::get_singleton();
|
||||
if (os) {
|
||||
os->set_open_with_filename(String::utf8([filename UTF8String]));
|
||||
}
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
// Open new instance.
|
||||
if (os && os->get_main_loop()) {
|
||||
List<String> args;
|
||||
args.push_back(os->get_open_with_filename());
|
||||
String exec = os->get_executable_path();
|
||||
os->create_process(exec, args);
|
||||
}
|
||||
#endif
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender {
|
||||
DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton();
|
||||
if (ds) {
|
||||
ds->send_window_event(ds->get_window(DisplayServerOSX::MAIN_WINDOW_ID), DisplayServerOSX::WINDOW_EVENT_CLOSE_REQUEST);
|
||||
}
|
||||
return NSTerminateCancel;
|
||||
}
|
||||
|
||||
- (void)showAbout:(id)sender {
|
||||
OS_OSX *os = (OS_OSX *)OS::get_singleton();
|
||||
if (os && os->get_main_loop()) {
|
||||
os->get_main_loop()->notification(MainLoop::NOTIFICATION_WM_ABOUT);
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@ -0,0 +1,65 @@
|
||||
/*************************************************************************/
|
||||
/* godot_content_view.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef GODOT_CONTENT_VIEW_H
|
||||
#define GODOT_CONTENT_VIEW_H
|
||||
|
||||
#include "servers/display_server.h"
|
||||
|
||||
#import <AppKit/AppKit.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#if defined(GLES3_ENABLED)
|
||||
#import <AppKit/NSOpenGLView.h>
|
||||
#define RootView NSOpenGLView
|
||||
#else
|
||||
#define RootView NSView
|
||||
#endif
|
||||
|
||||
#import <QuartzCore/CAMetalLayer.h>
|
||||
|
||||
@interface GodotContentView : RootView <NSTextInputClient> {
|
||||
DisplayServer::WindowID window_id;
|
||||
NSTrackingArea *tracking_area;
|
||||
NSMutableAttributedString *marked_text;
|
||||
bool ime_input_event_in_progress;
|
||||
bool mouse_down_control;
|
||||
bool ignore_momentum_scroll;
|
||||
}
|
||||
|
||||
- (void)processScrollEvent:(NSEvent *)event button:(MouseButton)button factor:(double)factor;
|
||||
- (void)processPanEvent:(NSEvent *)event dx:(double)dx dy:(double)dy;
|
||||
- (void)processMouseEvent:(NSEvent *)event index:(MouseButton)index mask:(MouseButton)mask pressed:(bool)pressed;
|
||||
- (void)setWindowID:(DisplayServer::WindowID)wid;
|
||||
- (void)cancelComposition;
|
||||
|
||||
@end
|
||||
|
||||
#endif // GODOT_CONTENT_VIEW_H
|
||||
@ -0,0 +1,760 @@
|
||||
/*************************************************************************/
|
||||
/* godot_content_view.mm */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "godot_content_view.h"
|
||||
|
||||
#include "display_server_osx.h"
|
||||
#include "key_mapping_osx.h"
|
||||
|
||||
@implementation GodotContentView
|
||||
|
||||
- (id)init {
|
||||
self = [super init];
|
||||
window_id = DisplayServer::INVALID_WINDOW_ID;
|
||||
tracking_area = nil;
|
||||
ime_input_event_in_progress = false;
|
||||
mouse_down_control = false;
|
||||
ignore_momentum_scroll = false;
|
||||
[self updateTrackingAreas];
|
||||
|
||||
if (@available(macOS 10.13, *)) {
|
||||
[self registerForDraggedTypes:[NSArray arrayWithObject:NSPasteboardTypeFileURL]];
|
||||
#if !defined(__aarch64__) // Do not build deprectead 10.13 code on ARM.
|
||||
} else {
|
||||
[self registerForDraggedTypes:[NSArray arrayWithObject:NSFilenamesPboardType]];
|
||||
#endif
|
||||
}
|
||||
marked_text = [[NSMutableAttributedString alloc] init];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setWindowID:(DisplayServerOSX::WindowID)wid {
|
||||
window_id = wid;
|
||||
}
|
||||
|
||||
// MARK: Backing Layer
|
||||
|
||||
- (CALayer *)makeBackingLayer {
|
||||
return [[CAMetalLayer class] layer];
|
||||
}
|
||||
|
||||
- (void)updateLayer {
|
||||
DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton();
|
||||
ds->window_update(window_id);
|
||||
[super updateLayer];
|
||||
}
|
||||
|
||||
- (BOOL)wantsUpdateLayer {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)isOpaque {
|
||||
return YES;
|
||||
}
|
||||
|
||||
// MARK: IME
|
||||
|
||||
- (BOOL)hasMarkedText {
|
||||
return (marked_text.length > 0);
|
||||
}
|
||||
|
||||
- (NSRange)markedRange {
|
||||
return NSMakeRange(0, marked_text.length);
|
||||
}
|
||||
|
||||
- (NSRange)selectedRange {
|
||||
static const NSRange kEmptyRange = { NSNotFound, 0 };
|
||||
return kEmptyRange;
|
||||
}
|
||||
|
||||
- (void)setMarkedText:(id)aString selectedRange:(NSRange)selectedRange replacementRange:(NSRange)replacementRange {
|
||||
if ([aString isKindOfClass:[NSAttributedString class]]) {
|
||||
marked_text = [[NSMutableAttributedString alloc] initWithAttributedString:aString];
|
||||
} else {
|
||||
marked_text = [[NSMutableAttributedString alloc] initWithString:aString];
|
||||
}
|
||||
if (marked_text.length == 0) {
|
||||
[self unmarkText];
|
||||
return;
|
||||
}
|
||||
|
||||
DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton();
|
||||
if (!ds || !ds->has_window(window_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
DisplayServerOSX::WindowData &wd = ds->get_window(window_id);
|
||||
if (wd.im_active) {
|
||||
ime_input_event_in_progress = true;
|
||||
ds->update_im_text(Point2i(selectedRange.location, selectedRange.length), String::utf8([[marked_text mutableString] UTF8String]));
|
||||
}
|
||||
}
|
||||
|
||||
- (void)unmarkText {
|
||||
ime_input_event_in_progress = false;
|
||||
[[marked_text mutableString] setString:@""];
|
||||
|
||||
DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton();
|
||||
if (!ds || !ds->has_window(window_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
DisplayServerOSX::WindowData &wd = ds->get_window(window_id);
|
||||
if (wd.im_active) {
|
||||
ds->update_im_text(Point2i(), String());
|
||||
}
|
||||
}
|
||||
|
||||
- (NSArray *)validAttributesForMarkedText {
|
||||
return [NSArray array];
|
||||
}
|
||||
|
||||
- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange {
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSUInteger)characterIndexForPoint:(NSPoint)aPoint {
|
||||
return 0;
|
||||
}
|
||||
|
||||
- (NSRect)firstRectForCharacterRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange {
|
||||
DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton();
|
||||
if (!ds || !ds->has_window(window_id)) {
|
||||
return NSMakeRect(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
DisplayServerOSX::WindowData &wd = ds->get_window(window_id);
|
||||
const NSRect content_rect = [wd.window_view frame];
|
||||
const float scale = ds->screen_get_max_scale();
|
||||
NSRect point_in_window_rect = NSMakeRect(wd.im_position.x / scale, content_rect.size.height - (wd.im_position.y / scale) - 1, 0, 0);
|
||||
NSPoint point_on_screen = [wd.window_object convertRectToScreen:point_in_window_rect].origin;
|
||||
|
||||
return NSMakeRect(point_on_screen.x, point_on_screen.y, 0, 0);
|
||||
}
|
||||
|
||||
- (void)cancelComposition {
|
||||
[self unmarkText];
|
||||
[[NSTextInputContext currentInputContext] discardMarkedText];
|
||||
}
|
||||
|
||||
- (void)insertText:(id)aString {
|
||||
[self insertText:aString replacementRange:NSMakeRange(0, 0)];
|
||||
}
|
||||
|
||||
- (void)insertText:(id)aString replacementRange:(NSRange)replacementRange {
|
||||
NSEvent *event = [NSApp currentEvent];
|
||||
|
||||
NSString *characters;
|
||||
if ([aString isKindOfClass:[NSAttributedString class]]) {
|
||||
characters = [aString string];
|
||||
} else {
|
||||
characters = (NSString *)aString;
|
||||
}
|
||||
|
||||
NSCharacterSet *ctrl_chars = [NSCharacterSet controlCharacterSet];
|
||||
NSCharacterSet *wsnl_chars = [NSCharacterSet whitespaceAndNewlineCharacterSet];
|
||||
if ([characters rangeOfCharacterFromSet:ctrl_chars].length && [characters rangeOfCharacterFromSet:wsnl_chars].length == 0) {
|
||||
[[NSTextInputContext currentInputContext] discardMarkedText];
|
||||
[self cancelComposition];
|
||||
return;
|
||||
}
|
||||
|
||||
DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton();
|
||||
if (!ds || !ds->has_window(window_id)) {
|
||||
[self cancelComposition];
|
||||
return;
|
||||
}
|
||||
|
||||
Char16String text;
|
||||
text.resize([characters length] + 1);
|
||||
[characters getCharacters:(unichar *)text.ptrw() range:NSMakeRange(0, [characters length])];
|
||||
|
||||
String u32text;
|
||||
u32text.parse_utf16(text.ptr(), text.length());
|
||||
|
||||
for (int i = 0; i < u32text.length(); i++) {
|
||||
const char32_t codepoint = u32text[i];
|
||||
if ((codepoint & 0xFF00) == 0xF700) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DisplayServerOSX::KeyEvent ke;
|
||||
|
||||
ke.window_id = window_id;
|
||||
ke.osx_state = [event modifierFlags];
|
||||
ke.pressed = true;
|
||||
ke.echo = false;
|
||||
ke.raw = false; // IME input event.
|
||||
ke.keycode = Key::NONE;
|
||||
ke.physical_keycode = Key::NONE;
|
||||
ke.unicode = codepoint;
|
||||
|
||||
ds->push_to_key_event_buffer(ke);
|
||||
}
|
||||
[self cancelComposition];
|
||||
}
|
||||
|
||||
// MARK: Drag and drop
|
||||
|
||||
- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender {
|
||||
return NSDragOperationCopy;
|
||||
}
|
||||
|
||||
- (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)sender {
|
||||
return NSDragOperationCopy;
|
||||
}
|
||||
|
||||
- (BOOL)performDragOperation:(id<NSDraggingInfo>)sender {
|
||||
DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton();
|
||||
if (!ds || !ds->has_window(window_id)) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
DisplayServerOSX::WindowData &wd = ds->get_window(window_id);
|
||||
if (!wd.drop_files_callback.is_null()) {
|
||||
Vector<String> files;
|
||||
NSPasteboard *pboard = [sender draggingPasteboard];
|
||||
|
||||
if (@available(macOS 10.13, *)) {
|
||||
NSArray *items = pboard.pasteboardItems;
|
||||
for (NSPasteboardItem *item in items) {
|
||||
NSString *url = [item stringForType:NSPasteboardTypeFileURL];
|
||||
NSString *file = [NSURL URLWithString:url].path;
|
||||
files.push_back(String::utf8([file UTF8String]));
|
||||
}
|
||||
#if !defined(__aarch64__) // Do not build deprectead 10.13 code on ARM.
|
||||
} else {
|
||||
NSArray *filenames = [pboard propertyListForType:NSFilenamesPboardType];
|
||||
for (NSString *file in filenames) {
|
||||
files.push_back(String::utf8([file UTF8String]));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
Variant v = files;
|
||||
Variant *vp = &v;
|
||||
Variant ret;
|
||||
Callable::CallError ce;
|
||||
wd.drop_files_callback.call((const Variant **)&vp, 1, ret, ce);
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
// MARK: Focus
|
||||
|
||||
- (BOOL)canBecomeKeyView {
|
||||
DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton();
|
||||
if (!ds || !ds->has_window(window_id)) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
DisplayServerOSX::WindowData &wd = ds->get_window(window_id);
|
||||
return !wd.no_focus;
|
||||
}
|
||||
|
||||
- (BOOL)acceptsFirstResponder {
|
||||
return YES;
|
||||
}
|
||||
|
||||
// MARK: Mouse
|
||||
|
||||
- (void)cursorUpdate:(NSEvent *)event {
|
||||
DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton();
|
||||
if (!ds) {
|
||||
return;
|
||||
}
|
||||
|
||||
ds->cursor_update_shape();
|
||||
}
|
||||
|
||||
- (void)processMouseEvent:(NSEvent *)event index:(MouseButton)index mask:(MouseButton)mask pressed:(bool)pressed {
|
||||
DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton();
|
||||
if (!ds || !ds->has_window(window_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
DisplayServerOSX::WindowData &wd = ds->get_window(window_id);
|
||||
MouseButton last_button_state = ds->mouse_get_button_state();
|
||||
|
||||
if (pressed) {
|
||||
last_button_state |= mask;
|
||||
} else {
|
||||
last_button_state &= (MouseButton)~mask;
|
||||
}
|
||||
ds->mouse_set_button_state(last_button_state);
|
||||
|
||||
Ref<InputEventMouseButton> mb;
|
||||
mb.instantiate();
|
||||
mb->set_window_id(window_id);
|
||||
ds->update_mouse_pos(wd, [event locationInWindow]);
|
||||
ds->get_key_modifier_state([event modifierFlags], mb);
|
||||
mb->set_button_index(index);
|
||||
mb->set_pressed(pressed);
|
||||
mb->set_position(wd.mouse_pos);
|
||||
mb->set_global_position(wd.mouse_pos);
|
||||
mb->set_button_mask(last_button_state);
|
||||
if (index == MouseButton::LEFT && pressed) {
|
||||
mb->set_double_click([event clickCount] == 2);
|
||||
}
|
||||
|
||||
Input::get_singleton()->parse_input_event(mb);
|
||||
}
|
||||
|
||||
- (void)mouseDown:(NSEvent *)event {
|
||||
if (([event modifierFlags] & NSEventModifierFlagControl)) {
|
||||
mouse_down_control = true;
|
||||
[self processMouseEvent:event index:MouseButton::RIGHT mask:MouseButton::MASK_RIGHT pressed:true];
|
||||
} else {
|
||||
mouse_down_control = false;
|
||||
[self processMouseEvent:event index:MouseButton::LEFT mask:MouseButton::MASK_LEFT pressed:true];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)mouseDragged:(NSEvent *)event {
|
||||
[self mouseMoved:event];
|
||||
}
|
||||
|
||||
- (void)mouseUp:(NSEvent *)event {
|
||||
if (mouse_down_control) {
|
||||
[self processMouseEvent:event index:MouseButton::RIGHT mask:MouseButton::MASK_RIGHT pressed:false];
|
||||
} else {
|
||||
[self processMouseEvent:event index:MouseButton::LEFT mask:MouseButton::MASK_LEFT pressed:false];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)mouseMoved:(NSEvent *)event {
|
||||
DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton();
|
||||
if (!ds || !ds->has_window(window_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
DisplayServerOSX::WindowData &wd = ds->get_window(window_id);
|
||||
|
||||
NSPoint delta = NSMakePoint([event deltaX], [event deltaY]);
|
||||
NSPoint mpos = [event locationInWindow];
|
||||
|
||||
if (ds->update_mouse_wrap(wd, delta, mpos, [event timestamp])) {
|
||||
return;
|
||||
}
|
||||
|
||||
Ref<InputEventMouseMotion> mm;
|
||||
mm.instantiate();
|
||||
|
||||
mm->set_window_id(window_id);
|
||||
mm->set_button_mask(ds->mouse_get_button_state());
|
||||
ds->update_mouse_pos(wd, mpos);
|
||||
mm->set_position(wd.mouse_pos);
|
||||
mm->set_pressure([event pressure]);
|
||||
if ([event subtype] == NSEventSubtypeTabletPoint) {
|
||||
const NSPoint p = [event tilt];
|
||||
mm->set_tilt(Vector2(p.x, p.y));
|
||||
}
|
||||
mm->set_global_position(wd.mouse_pos);
|
||||
mm->set_velocity(Input::get_singleton()->get_last_mouse_velocity());
|
||||
const Vector2i relativeMotion = Vector2i(delta.x, delta.y) * ds->screen_get_max_scale();
|
||||
mm->set_relative(relativeMotion);
|
||||
ds->get_key_modifier_state([event modifierFlags], mm);
|
||||
|
||||
Input::get_singleton()->parse_input_event(mm);
|
||||
}
|
||||
|
||||
- (void)rightMouseDown:(NSEvent *)event {
|
||||
[self processMouseEvent:event index:MouseButton::RIGHT mask:MouseButton::MASK_RIGHT pressed:true];
|
||||
}
|
||||
|
||||
- (void)rightMouseDragged:(NSEvent *)event {
|
||||
[self mouseMoved:event];
|
||||
}
|
||||
|
||||
- (void)rightMouseUp:(NSEvent *)event {
|
||||
[self processMouseEvent:event index:MouseButton::RIGHT mask:MouseButton::MASK_RIGHT pressed:false];
|
||||
}
|
||||
|
||||
- (void)otherMouseDown:(NSEvent *)event {
|
||||
if ((int)[event buttonNumber] == 2) {
|
||||
[self processMouseEvent:event index:MouseButton::MIDDLE mask:MouseButton::MASK_MIDDLE pressed:true];
|
||||
} else if ((int)[event buttonNumber] == 3) {
|
||||
[self processMouseEvent:event index:MouseButton::MB_XBUTTON1 mask:MouseButton::MASK_XBUTTON1 pressed:true];
|
||||
} else if ((int)[event buttonNumber] == 4) {
|
||||
[self processMouseEvent:event index:MouseButton::MB_XBUTTON2 mask:MouseButton::MASK_XBUTTON2 pressed:true];
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)otherMouseDragged:(NSEvent *)event {
|
||||
[self mouseMoved:event];
|
||||
}
|
||||
|
||||
- (void)otherMouseUp:(NSEvent *)event {
|
||||
if ((int)[event buttonNumber] == 2) {
|
||||
[self processMouseEvent:event index:MouseButton::MIDDLE mask:MouseButton::MASK_MIDDLE pressed:false];
|
||||
} else if ((int)[event buttonNumber] == 3) {
|
||||
[self processMouseEvent:event index:MouseButton::MB_XBUTTON1 mask:MouseButton::MASK_XBUTTON1 pressed:false];
|
||||
} else if ((int)[event buttonNumber] == 4) {
|
||||
[self processMouseEvent:event index:MouseButton::MB_XBUTTON2 mask:MouseButton::MASK_XBUTTON2 pressed:false];
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)mouseExited:(NSEvent *)event {
|
||||
DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton();
|
||||
if (!ds || !ds->has_window(window_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
DisplayServerOSX::WindowData &wd = ds->get_window(window_id);
|
||||
if (ds->mouse_get_mode() != DisplayServer::MOUSE_MODE_CAPTURED) {
|
||||
ds->send_window_event(wd, DisplayServerOSX::WINDOW_EVENT_MOUSE_EXIT);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)mouseEntered:(NSEvent *)event {
|
||||
DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton();
|
||||
if (!ds || !ds->has_window(window_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
DisplayServerOSX::WindowData &wd = ds->get_window(window_id);
|
||||
if (ds->mouse_get_mode() != DisplayServer::MOUSE_MODE_CAPTURED) {
|
||||
ds->send_window_event(wd, DisplayServerOSX::WINDOW_EVENT_MOUSE_ENTER);
|
||||
}
|
||||
|
||||
ds->cursor_update_shape();
|
||||
}
|
||||
|
||||
- (void)magnifyWithEvent:(NSEvent *)event {
|
||||
DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton();
|
||||
if (!ds || !ds->has_window(window_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
DisplayServerOSX::WindowData &wd = ds->get_window(window_id);
|
||||
|
||||
Ref<InputEventMagnifyGesture> ev;
|
||||
ev.instantiate();
|
||||
ev->set_window_id(window_id);
|
||||
ds->get_key_modifier_state([event modifierFlags], ev);
|
||||
ds->update_mouse_pos(wd, [event locationInWindow]);
|
||||
ev->set_position(wd.mouse_pos);
|
||||
ev->set_factor([event magnification] + 1.0);
|
||||
|
||||
Input::get_singleton()->parse_input_event(ev);
|
||||
}
|
||||
|
||||
- (void)updateTrackingAreas {
|
||||
if (tracking_area != nil) {
|
||||
[self removeTrackingArea:tracking_area];
|
||||
}
|
||||
|
||||
NSTrackingAreaOptions options = NSTrackingMouseEnteredAndExited | NSTrackingActiveInKeyWindow | NSTrackingCursorUpdate | NSTrackingInVisibleRect;
|
||||
tracking_area = [[NSTrackingArea alloc] initWithRect:[self bounds] options:options owner:self userInfo:nil];
|
||||
|
||||
[self addTrackingArea:tracking_area];
|
||||
[super updateTrackingAreas];
|
||||
}
|
||||
|
||||
// MARK: Keyboard
|
||||
|
||||
- (void)keyDown:(NSEvent *)event {
|
||||
DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton();
|
||||
if (!ds || !ds->has_window(window_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
DisplayServerOSX::WindowData &wd = ds->get_window(window_id);
|
||||
|
||||
ignore_momentum_scroll = true;
|
||||
|
||||
// Ignore all input if IME input is in progress.
|
||||
if (!ime_input_event_in_progress) {
|
||||
NSString *characters = [event characters];
|
||||
NSUInteger length = [characters length];
|
||||
|
||||
if (!wd.im_active && length > 0 && keycode_has_unicode(KeyMappingOSX::remap_key([event keyCode], [event modifierFlags]))) {
|
||||
// Fallback unicode character handler used if IME is not active.
|
||||
Char16String text;
|
||||
text.resize([characters length] + 1);
|
||||
[characters getCharacters:(unichar *)text.ptrw() range:NSMakeRange(0, [characters length])];
|
||||
|
||||
String u32text;
|
||||
u32text.parse_utf16(text.ptr(), text.length());
|
||||
|
||||
for (int i = 0; i < u32text.length(); i++) {
|
||||
const char32_t codepoint = u32text[i];
|
||||
|
||||
DisplayServerOSX::KeyEvent ke;
|
||||
|
||||
ke.window_id = window_id;
|
||||
ke.osx_state = [event modifierFlags];
|
||||
ke.pressed = true;
|
||||
ke.echo = [event isARepeat];
|
||||
ke.keycode = KeyMappingOSX::remap_key([event keyCode], [event modifierFlags]);
|
||||
ke.physical_keycode = KeyMappingOSX::translate_key([event keyCode]);
|
||||
ke.raw = true;
|
||||
ke.unicode = codepoint;
|
||||
|
||||
ds->push_to_key_event_buffer(ke);
|
||||
}
|
||||
} else {
|
||||
DisplayServerOSX::KeyEvent ke;
|
||||
|
||||
ke.window_id = window_id;
|
||||
ke.osx_state = [event modifierFlags];
|
||||
ke.pressed = true;
|
||||
ke.echo = [event isARepeat];
|
||||
ke.keycode = KeyMappingOSX::remap_key([event keyCode], [event modifierFlags]);
|
||||
ke.physical_keycode = KeyMappingOSX::translate_key([event keyCode]);
|
||||
ke.raw = false;
|
||||
ke.unicode = 0;
|
||||
|
||||
ds->push_to_key_event_buffer(ke);
|
||||
}
|
||||
}
|
||||
|
||||
// Pass events to IME handler
|
||||
if (wd.im_active) {
|
||||
[self interpretKeyEvents:[NSArray arrayWithObject:event]];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)flagsChanged:(NSEvent *)event {
|
||||
DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton();
|
||||
if (!ds || !ds->has_window(window_id)) {
|
||||
return;
|
||||
}
|
||||
ignore_momentum_scroll = true;
|
||||
|
||||
// Ignore all input if IME input is in progress
|
||||
if (!ime_input_event_in_progress) {
|
||||
DisplayServerOSX::KeyEvent ke;
|
||||
|
||||
ke.window_id = window_id;
|
||||
ke.echo = false;
|
||||
ke.raw = true;
|
||||
|
||||
int key = [event keyCode];
|
||||
int mod = [event modifierFlags];
|
||||
|
||||
if (key == 0x36 || key == 0x37) {
|
||||
if (mod & NSEventModifierFlagCommand) {
|
||||
mod &= ~NSEventModifierFlagCommand;
|
||||
ke.pressed = true;
|
||||
} else {
|
||||
ke.pressed = false;
|
||||
}
|
||||
} else if (key == 0x38 || key == 0x3c) {
|
||||
if (mod & NSEventModifierFlagShift) {
|
||||
mod &= ~NSEventModifierFlagShift;
|
||||
ke.pressed = true;
|
||||
} else {
|
||||
ke.pressed = false;
|
||||
}
|
||||
} else if (key == 0x3a || key == 0x3d) {
|
||||
if (mod & NSEventModifierFlagOption) {
|
||||
mod &= ~NSEventModifierFlagOption;
|
||||
ke.pressed = true;
|
||||
} else {
|
||||
ke.pressed = false;
|
||||
}
|
||||
} else if (key == 0x3b || key == 0x3e) {
|
||||
if (mod & NSEventModifierFlagControl) {
|
||||
mod &= ~NSEventModifierFlagControl;
|
||||
ke.pressed = true;
|
||||
} else {
|
||||
ke.pressed = false;
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
ke.osx_state = mod;
|
||||
ke.keycode = KeyMappingOSX::remap_key(key, mod);
|
||||
ke.physical_keycode = KeyMappingOSX::translate_key(key);
|
||||
ke.unicode = 0;
|
||||
|
||||
ds->push_to_key_event_buffer(ke);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)keyUp:(NSEvent *)event {
|
||||
DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton();
|
||||
if (!ds || !ds->has_window(window_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
DisplayServerOSX::WindowData &wd = ds->get_window(window_id);
|
||||
|
||||
// Ignore all input if IME input is in progress.
|
||||
if (!ime_input_event_in_progress) {
|
||||
NSString *characters = [event characters];
|
||||
NSUInteger length = [characters length];
|
||||
|
||||
// Fallback unicode character handler used if IME is not active.
|
||||
if (!wd.im_active && length > 0 && keycode_has_unicode(KeyMappingOSX::remap_key([event keyCode], [event modifierFlags]))) {
|
||||
Char16String text;
|
||||
text.resize([characters length] + 1);
|
||||
[characters getCharacters:(unichar *)text.ptrw() range:NSMakeRange(0, [characters length])];
|
||||
|
||||
String u32text;
|
||||
u32text.parse_utf16(text.ptr(), text.length());
|
||||
|
||||
for (int i = 0; i < u32text.length(); i++) {
|
||||
const char32_t codepoint = u32text[i];
|
||||
DisplayServerOSX::KeyEvent ke;
|
||||
|
||||
ke.window_id = window_id;
|
||||
ke.osx_state = [event modifierFlags];
|
||||
ke.pressed = false;
|
||||
ke.echo = [event isARepeat];
|
||||
ke.keycode = KeyMappingOSX::remap_key([event keyCode], [event modifierFlags]);
|
||||
ke.physical_keycode = KeyMappingOSX::translate_key([event keyCode]);
|
||||
ke.raw = true;
|
||||
ke.unicode = codepoint;
|
||||
|
||||
ds->push_to_key_event_buffer(ke);
|
||||
}
|
||||
} else {
|
||||
DisplayServerOSX::KeyEvent ke;
|
||||
|
||||
ke.window_id = window_id;
|
||||
ke.osx_state = [event modifierFlags];
|
||||
ke.pressed = false;
|
||||
ke.echo = [event isARepeat];
|
||||
ke.keycode = KeyMappingOSX::remap_key([event keyCode], [event modifierFlags]);
|
||||
ke.physical_keycode = KeyMappingOSX::translate_key([event keyCode]);
|
||||
ke.raw = true;
|
||||
ke.unicode = 0;
|
||||
|
||||
ds->push_to_key_event_buffer(ke);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Scroll and pan
|
||||
|
||||
- (void)processScrollEvent:(NSEvent *)event button:(MouseButton)button factor:(double)factor {
|
||||
DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton();
|
||||
if (!ds || !ds->has_window(window_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
DisplayServerOSX::WindowData &wd = ds->get_window(window_id);
|
||||
MouseButton mask = mouse_button_to_mask(button);
|
||||
|
||||
Ref<InputEventMouseButton> sc;
|
||||
sc.instantiate();
|
||||
|
||||
sc->set_window_id(window_id);
|
||||
ds->get_key_modifier_state([event modifierFlags], sc);
|
||||
sc->set_button_index(button);
|
||||
sc->set_factor(factor);
|
||||
sc->set_pressed(true);
|
||||
sc->set_position(wd.mouse_pos);
|
||||
sc->set_global_position(wd.mouse_pos);
|
||||
MouseButton last_button_state = ds->mouse_get_button_state() | (MouseButton)mask;
|
||||
sc->set_button_mask(last_button_state);
|
||||
ds->mouse_set_button_state(last_button_state);
|
||||
|
||||
Input::get_singleton()->parse_input_event(sc);
|
||||
|
||||
sc.instantiate();
|
||||
sc->set_window_id(window_id);
|
||||
sc->set_button_index(button);
|
||||
sc->set_factor(factor);
|
||||
sc->set_pressed(false);
|
||||
sc->set_position(wd.mouse_pos);
|
||||
sc->set_global_position(wd.mouse_pos);
|
||||
last_button_state &= (MouseButton)~mask;
|
||||
sc->set_button_mask(last_button_state);
|
||||
ds->mouse_set_button_state(last_button_state);
|
||||
|
||||
Input::get_singleton()->parse_input_event(sc);
|
||||
}
|
||||
|
||||
- (void)processPanEvent:(NSEvent *)event dx:(double)dx dy:(double)dy {
|
||||
DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton();
|
||||
if (!ds || !ds->has_window(window_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
DisplayServerOSX::WindowData &wd = ds->get_window(window_id);
|
||||
|
||||
Ref<InputEventPanGesture> pg;
|
||||
pg.instantiate();
|
||||
|
||||
pg->set_window_id(window_id);
|
||||
ds->get_key_modifier_state([event modifierFlags], pg);
|
||||
pg->set_position(wd.mouse_pos);
|
||||
pg->set_delta(Vector2(-dx, -dy));
|
||||
|
||||
Input::get_singleton()->parse_input_event(pg);
|
||||
}
|
||||
|
||||
- (void)scrollWheel:(NSEvent *)event {
|
||||
DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton();
|
||||
if (!ds || !ds->has_window(window_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
DisplayServerOSX::WindowData &wd = ds->get_window(window_id);
|
||||
ds->update_mouse_pos(wd, [event locationInWindow]);
|
||||
|
||||
double delta_x = [event scrollingDeltaX];
|
||||
double delta_y = [event scrollingDeltaY];
|
||||
|
||||
if ([event hasPreciseScrollingDeltas]) {
|
||||
delta_x *= 0.03;
|
||||
delta_y *= 0.03;
|
||||
}
|
||||
|
||||
if ([event momentumPhase] != NSEventPhaseNone) {
|
||||
if (ignore_momentum_scroll) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
ignore_momentum_scroll = false;
|
||||
}
|
||||
|
||||
if ([event phase] != NSEventPhaseNone || [event momentumPhase] != NSEventPhaseNone) {
|
||||
[self processPanEvent:event dx:delta_x dy:delta_y];
|
||||
} else {
|
||||
if (fabs(delta_x)) {
|
||||
[self processScrollEvent:event button:(0 > delta_x ? MouseButton::WHEEL_RIGHT : MouseButton::WHEEL_LEFT) factor:fabs(delta_x * 0.3)];
|
||||
}
|
||||
if (fabs(delta_y)) {
|
||||
[self processScrollEvent:event button:(0 < delta_y ? MouseButton::WHEEL_UP : MouseButton::WHEEL_DOWN) factor:fabs(delta_y * 0.3)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@ -0,0 +1,52 @@
|
||||
/*************************************************************************/
|
||||
/* godot_menu_item.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef GODOT_MENU_ITEM_H
|
||||
#define GODOT_MENU_ITEM_H
|
||||
|
||||
#include "servers/display_server.h"
|
||||
|
||||
#import <AppKit/AppKit.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface GodotMenuItem : NSObject {
|
||||
@public
|
||||
Callable callback;
|
||||
Variant meta;
|
||||
int id;
|
||||
bool checkable;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation GodotMenuItem
|
||||
@end
|
||||
|
||||
#endif // GODOT_MENU_ITEM_H
|
||||
@ -0,0 +1,47 @@
|
||||
/*************************************************************************/
|
||||
/* godot_window.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef GODOT_WINDOW_H
|
||||
#define GODOT_WINDOW_H
|
||||
|
||||
#include "servers/display_server.h"
|
||||
|
||||
#import <AppKit/AppKit.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface GodotWindow : NSWindow {
|
||||
DisplayServer::WindowID window_id;
|
||||
}
|
||||
|
||||
- (void)setWindowID:(DisplayServer::WindowID)wid;
|
||||
|
||||
@end
|
||||
|
||||
#endif //GODOT_WINDOW_H
|
||||
@ -0,0 +1,69 @@
|
||||
/*************************************************************************/
|
||||
/* godot_window.mm */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "godot_window.h"
|
||||
|
||||
#include "display_server_osx.h"
|
||||
|
||||
@implementation GodotWindow
|
||||
|
||||
- (id)init {
|
||||
self = [super init];
|
||||
window_id = DisplayServer::INVALID_WINDOW_ID;
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setWindowID:(DisplayServerOSX::WindowID)wid {
|
||||
window_id = wid;
|
||||
}
|
||||
|
||||
- (BOOL)canBecomeKeyWindow {
|
||||
// Required for NSBorderlessWindowMask windows.
|
||||
DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton();
|
||||
if (!ds || !ds->has_window(window_id)) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
DisplayServerOSX::WindowData &wd = ds->get_window(window_id);
|
||||
return !wd.no_focus;
|
||||
}
|
||||
|
||||
- (BOOL)canBecomeMainWindow {
|
||||
// Required for NSBorderlessWindowMask windows.
|
||||
DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton();
|
||||
if (!ds || !ds->has_window(window_id)) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
DisplayServerOSX::WindowData &wd = ds->get_window(window_id);
|
||||
return !wd.no_focus;
|
||||
}
|
||||
|
||||
@end
|
||||
@ -0,0 +1,47 @@
|
||||
/*************************************************************************/
|
||||
/* godot_window_delegate.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef GODOT_WINDOW_DELEGATE_H
|
||||
#define GODOT_WINDOW_DELEGATE_H
|
||||
|
||||
#include "servers/display_server.h"
|
||||
|
||||
#import <AppKit/AppKit.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface GodotWindowDelegate : NSObject <NSWindowDelegate> {
|
||||
DisplayServer::WindowID window_id;
|
||||
}
|
||||
|
||||
- (void)setWindowID:(DisplayServer::WindowID)wid;
|
||||
|
||||
@end
|
||||
|
||||
#endif //GODOT_WINDOW_DELEGATE_H
|
||||
@ -0,0 +1,254 @@
|
||||
/*************************************************************************/
|
||||
/* godot_window_delegate.mm */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "godot_window_delegate.h"
|
||||
|
||||
#include "display_server_osx.h"
|
||||
|
||||
@implementation GodotWindowDelegate
|
||||
|
||||
- (void)setWindowID:(DisplayServer::WindowID)wid {
|
||||
window_id = wid;
|
||||
}
|
||||
|
||||
- (BOOL)windowShouldClose:(id)sender {
|
||||
DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton();
|
||||
if (!ds || !ds->has_window(window_id)) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
ds->send_window_event(ds->get_window(window_id), DisplayServerOSX::WINDOW_EVENT_CLOSE_REQUEST);
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)windowWillClose:(NSNotification *)notification {
|
||||
DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton();
|
||||
if (!ds || !ds->has_window(window_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
DisplayServerOSX::WindowData &wd = ds->get_window(window_id);
|
||||
while (wd.transient_children.size()) {
|
||||
ds->window_set_transient(wd.transient_children.front()->get(), DisplayServerOSX::INVALID_WINDOW_ID);
|
||||
}
|
||||
|
||||
if (wd.transient_parent != DisplayServerOSX::INVALID_WINDOW_ID) {
|
||||
ds->window_set_transient(window_id, DisplayServerOSX::INVALID_WINDOW_ID);
|
||||
}
|
||||
|
||||
ds->window_destroy(window_id);
|
||||
}
|
||||
|
||||
- (void)windowDidEnterFullScreen:(NSNotification *)notification {
|
||||
DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton();
|
||||
if (!ds || !ds->has_window(window_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
DisplayServerOSX::WindowData &wd = ds->get_window(window_id);
|
||||
wd.fullscreen = true;
|
||||
// Reset window size limits.
|
||||
[wd.window_object setContentMinSize:NSMakeSize(0, 0)];
|
||||
[wd.window_object setContentMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)];
|
||||
|
||||
// Force window resize event.
|
||||
[self windowDidResize:notification];
|
||||
}
|
||||
|
||||
- (void)windowDidExitFullScreen:(NSNotification *)notification {
|
||||
DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton();
|
||||
if (!ds || !ds->has_window(window_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
DisplayServerOSX::WindowData &wd = ds->get_window(window_id);
|
||||
wd.fullscreen = false;
|
||||
|
||||
// Set window size limits.
|
||||
const float scale = ds->screen_get_max_scale();
|
||||
if (wd.min_size != Size2i()) {
|
||||
Size2i size = wd.min_size / scale;
|
||||
[wd.window_object setContentMinSize:NSMakeSize(size.x, size.y)];
|
||||
}
|
||||
if (wd.max_size != Size2i()) {
|
||||
Size2i size = wd.max_size / scale;
|
||||
[wd.window_object setContentMaxSize:NSMakeSize(size.x, size.y)];
|
||||
}
|
||||
|
||||
// Restore resizability state.
|
||||
if (wd.resize_disabled) {
|
||||
[wd.window_object setStyleMask:[wd.window_object styleMask] & ~NSWindowStyleMaskResizable];
|
||||
}
|
||||
|
||||
// Restore on-top state.
|
||||
if (wd.on_top) {
|
||||
[wd.window_object setLevel:NSFloatingWindowLevel];
|
||||
}
|
||||
|
||||
// Force window resize event.
|
||||
[self windowDidResize:notification];
|
||||
}
|
||||
|
||||
- (void)windowDidChangeBackingProperties:(NSNotification *)notification {
|
||||
DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton();
|
||||
if (!ds || !ds->has_window(window_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
DisplayServerOSX::WindowData &wd = ds->get_window(window_id);
|
||||
|
||||
CGFloat new_scale_factor = [wd.window_object backingScaleFactor];
|
||||
CGFloat old_scale_factor = [[[notification userInfo] objectForKey:@"NSBackingPropertyOldScaleFactorKey"] doubleValue];
|
||||
|
||||
if (new_scale_factor != old_scale_factor) {
|
||||
// Set new display scale and window size.
|
||||
const float scale = ds->screen_get_max_scale();
|
||||
const NSRect content_rect = [wd.window_view frame];
|
||||
|
||||
wd.size.width = content_rect.size.width * scale;
|
||||
wd.size.height = content_rect.size.height * scale;
|
||||
|
||||
ds->send_window_event(wd, DisplayServerOSX::WINDOW_EVENT_DPI_CHANGE);
|
||||
|
||||
CALayer *layer = [wd.window_view layer];
|
||||
if (layer) {
|
||||
layer.contentsScale = scale;
|
||||
}
|
||||
|
||||
//Force window resize event
|
||||
[self windowDidResize:notification];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)windowDidResize:(NSNotification *)notification {
|
||||
DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton();
|
||||
if (!ds || !ds->has_window(window_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
DisplayServerOSX::WindowData &wd = ds->get_window(window_id);
|
||||
const NSRect content_rect = [wd.window_view frame];
|
||||
const float scale = ds->screen_get_max_scale();
|
||||
wd.size.width = content_rect.size.width * scale;
|
||||
wd.size.height = content_rect.size.height * scale;
|
||||
|
||||
CALayer *layer = [wd.window_view layer];
|
||||
if (layer) {
|
||||
layer.contentsScale = scale;
|
||||
}
|
||||
|
||||
ds->window_resize(window_id, wd.size.width, wd.size.height);
|
||||
|
||||
if (!wd.rect_changed_callback.is_null()) {
|
||||
Variant size = Rect2i(ds->window_get_position(window_id), ds->window_get_size(window_id));
|
||||
Variant *sizep = &size;
|
||||
Variant ret;
|
||||
Callable::CallError ce;
|
||||
wd.rect_changed_callback.call((const Variant **)&sizep, 1, ret, ce);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)windowDidMove:(NSNotification *)notification {
|
||||
DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton();
|
||||
if (!ds || !ds->has_window(window_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
DisplayServerOSX::WindowData &wd = ds->get_window(window_id);
|
||||
ds->release_pressed_events();
|
||||
|
||||
if (!wd.rect_changed_callback.is_null()) {
|
||||
Variant size = Rect2i(ds->window_get_position(window_id), ds->window_get_size(window_id));
|
||||
Variant *sizep = &size;
|
||||
Variant ret;
|
||||
Callable::CallError ce;
|
||||
wd.rect_changed_callback.call((const Variant **)&sizep, 1, ret, ce);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)windowDidBecomeKey:(NSNotification *)notification {
|
||||
DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton();
|
||||
if (!ds || !ds->has_window(window_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
DisplayServerOSX::WindowData &wd = ds->get_window(window_id);
|
||||
|
||||
if (ds->mouse_get_mode() == DisplayServer::MOUSE_MODE_CAPTURED) {
|
||||
const NSRect content_rect = [wd.window_view frame];
|
||||
NSRect point_in_window_rect = NSMakeRect(content_rect.size.width / 2, content_rect.size.height / 2, 0, 0);
|
||||
NSPoint point_on_screen = [[wd.window_view window] convertRectToScreen:point_in_window_rect].origin;
|
||||
CGPoint mouse_warp_pos = { point_on_screen.x, CGDisplayBounds(CGMainDisplayID()).size.height - point_on_screen.y };
|
||||
CGWarpMouseCursorPosition(mouse_warp_pos);
|
||||
} else {
|
||||
ds->update_mouse_pos(wd, [wd.window_object mouseLocationOutsideOfEventStream]);
|
||||
}
|
||||
|
||||
ds->set_last_focused_window(window_id);
|
||||
ds->send_window_event(wd, DisplayServerOSX::WINDOW_EVENT_FOCUS_IN);
|
||||
}
|
||||
|
||||
- (void)windowDidResignKey:(NSNotification *)notification {
|
||||
DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton();
|
||||
if (!ds || !ds->has_window(window_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
DisplayServerOSX::WindowData &wd = ds->get_window(window_id);
|
||||
|
||||
ds->release_pressed_events();
|
||||
ds->send_window_event(wd, DisplayServerOSX::WINDOW_EVENT_FOCUS_OUT);
|
||||
}
|
||||
|
||||
- (void)windowDidMiniaturize:(NSNotification *)notification {
|
||||
DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton();
|
||||
if (!ds || !ds->has_window(window_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
DisplayServerOSX::WindowData &wd = ds->get_window(window_id);
|
||||
|
||||
ds->release_pressed_events();
|
||||
ds->send_window_event(wd, DisplayServerOSX::WINDOW_EVENT_FOCUS_OUT);
|
||||
}
|
||||
|
||||
- (void)windowDidDeminiaturize:(NSNotification *)notification {
|
||||
DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton();
|
||||
if (!ds || !ds->has_window(window_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
DisplayServerOSX::WindowData &wd = ds->get_window(window_id);
|
||||
|
||||
ds->set_last_focused_window(window_id);
|
||||
ds->send_window_event(wd, DisplayServerOSX::WINDOW_EVENT_FOCUS_IN);
|
||||
}
|
||||
|
||||
@end
|
||||
@ -0,0 +1,52 @@
|
||||
/*************************************************************************/
|
||||
/* key_mapping_osx.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef KEY_MAPPING_OSX_H
|
||||
#define KEY_MAPPING_OSX_H
|
||||
|
||||
#include "core/os/keyboard.h"
|
||||
|
||||
class KeyMappingOSX {
|
||||
KeyMappingOSX() {}
|
||||
|
||||
static bool is_numpad_key(unsigned int key);
|
||||
|
||||
public:
|
||||
// Mappings input.
|
||||
static Key translate_key(unsigned int key);
|
||||
static unsigned int unmap_key(Key key);
|
||||
static Key remap_key(unsigned int key, unsigned int state);
|
||||
|
||||
// Mapping for menu shortcuts.
|
||||
static String keycode_get_native_string(Key p_keycode);
|
||||
static unsigned int keycode_get_native_mask(Key p_keycode);
|
||||
};
|
||||
|
||||
#endif // KEY_MAPPING_OSX_H
|
||||
@ -0,0 +1,477 @@
|
||||
/*************************************************************************/
|
||||
/* key_mapping_osx.mm */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "key_mapping_osx.h"
|
||||
|
||||
#include <Carbon/Carbon.h>
|
||||
#include <Cocoa/Cocoa.h>
|
||||
|
||||
bool KeyMappingOSX::is_numpad_key(unsigned int key) {
|
||||
static const unsigned int table[] = {
|
||||
0x41, /* kVK_ANSI_KeypadDecimal */
|
||||
0x43, /* kVK_ANSI_KeypadMultiply */
|
||||
0x45, /* kVK_ANSI_KeypadPlus */
|
||||
0x47, /* kVK_ANSI_KeypadClear */
|
||||
0x4b, /* kVK_ANSI_KeypadDivide */
|
||||
0x4c, /* kVK_ANSI_KeypadEnter */
|
||||
0x4e, /* kVK_ANSI_KeypadMinus */
|
||||
0x51, /* kVK_ANSI_KeypadEquals */
|
||||
0x52, /* kVK_ANSI_Keypad0 */
|
||||
0x53, /* kVK_ANSI_Keypad1 */
|
||||
0x54, /* kVK_ANSI_Keypad2 */
|
||||
0x55, /* kVK_ANSI_Keypad3 */
|
||||
0x56, /* kVK_ANSI_Keypad4 */
|
||||
0x57, /* kVK_ANSI_Keypad5 */
|
||||
0x58, /* kVK_ANSI_Keypad6 */
|
||||
0x59, /* kVK_ANSI_Keypad7 */
|
||||
0x5b, /* kVK_ANSI_Keypad8 */
|
||||
0x5c, /* kVK_ANSI_Keypad9 */
|
||||
0x5f, /* kVK_JIS_KeypadComma */
|
||||
0x00
|
||||
};
|
||||
for (int i = 0; table[i] != 0; i++) {
|
||||
if (key == table[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Keyboard symbol translation table.
|
||||
static const Key _osx_to_godot_table[128] = {
|
||||
/* 00 */ Key::A,
|
||||
/* 01 */ Key::S,
|
||||
/* 02 */ Key::D,
|
||||
/* 03 */ Key::F,
|
||||
/* 04 */ Key::H,
|
||||
/* 05 */ Key::G,
|
||||
/* 06 */ Key::Z,
|
||||
/* 07 */ Key::X,
|
||||
/* 08 */ Key::C,
|
||||
/* 09 */ Key::V,
|
||||
/* 0a */ Key::SECTION, /* ISO Section */
|
||||
/* 0b */ Key::B,
|
||||
/* 0c */ Key::Q,
|
||||
/* 0d */ Key::W,
|
||||
/* 0e */ Key::E,
|
||||
/* 0f */ Key::R,
|
||||
/* 10 */ Key::Y,
|
||||
/* 11 */ Key::T,
|
||||
/* 12 */ Key::KEY_1,
|
||||
/* 13 */ Key::KEY_2,
|
||||
/* 14 */ Key::KEY_3,
|
||||
/* 15 */ Key::KEY_4,
|
||||
/* 16 */ Key::KEY_6,
|
||||
/* 17 */ Key::KEY_5,
|
||||
/* 18 */ Key::EQUAL,
|
||||
/* 19 */ Key::KEY_9,
|
||||
/* 1a */ Key::KEY_7,
|
||||
/* 1b */ Key::MINUS,
|
||||
/* 1c */ Key::KEY_8,
|
||||
/* 1d */ Key::KEY_0,
|
||||
/* 1e */ Key::BRACERIGHT,
|
||||
/* 1f */ Key::O,
|
||||
/* 20 */ Key::U,
|
||||
/* 21 */ Key::BRACELEFT,
|
||||
/* 22 */ Key::I,
|
||||
/* 23 */ Key::P,
|
||||
/* 24 */ Key::ENTER,
|
||||
/* 25 */ Key::L,
|
||||
/* 26 */ Key::J,
|
||||
/* 27 */ Key::APOSTROPHE,
|
||||
/* 28 */ Key::K,
|
||||
/* 29 */ Key::SEMICOLON,
|
||||
/* 2a */ Key::BACKSLASH,
|
||||
/* 2b */ Key::COMMA,
|
||||
/* 2c */ Key::SLASH,
|
||||
/* 2d */ Key::N,
|
||||
/* 2e */ Key::M,
|
||||
/* 2f */ Key::PERIOD,
|
||||
/* 30 */ Key::TAB,
|
||||
/* 31 */ Key::SPACE,
|
||||
/* 32 */ Key::QUOTELEFT,
|
||||
/* 33 */ Key::BACKSPACE,
|
||||
/* 34 */ Key::UNKNOWN,
|
||||
/* 35 */ Key::ESCAPE,
|
||||
/* 36 */ Key::META,
|
||||
/* 37 */ Key::META,
|
||||
/* 38 */ Key::SHIFT,
|
||||
/* 39 */ Key::CAPSLOCK,
|
||||
/* 3a */ Key::ALT,
|
||||
/* 3b */ Key::CTRL,
|
||||
/* 3c */ Key::SHIFT,
|
||||
/* 3d */ Key::ALT,
|
||||
/* 3e */ Key::CTRL,
|
||||
/* 3f */ Key::UNKNOWN, /* Function */
|
||||
/* 40 */ Key::UNKNOWN, /* F17 */
|
||||
/* 41 */ Key::KP_PERIOD,
|
||||
/* 42 */ Key::UNKNOWN,
|
||||
/* 43 */ Key::KP_MULTIPLY,
|
||||
/* 44 */ Key::UNKNOWN,
|
||||
/* 45 */ Key::KP_ADD,
|
||||
/* 46 */ Key::UNKNOWN,
|
||||
/* 47 */ Key::NUMLOCK, /* Really KeypadClear... */
|
||||
/* 48 */ Key::VOLUMEUP, /* VolumeUp */
|
||||
/* 49 */ Key::VOLUMEDOWN, /* VolumeDown */
|
||||
/* 4a */ Key::VOLUMEMUTE, /* Mute */
|
||||
/* 4b */ Key::KP_DIVIDE,
|
||||
/* 4c */ Key::KP_ENTER,
|
||||
/* 4d */ Key::UNKNOWN,
|
||||
/* 4e */ Key::KP_SUBTRACT,
|
||||
/* 4f */ Key::UNKNOWN, /* F18 */
|
||||
/* 50 */ Key::UNKNOWN, /* F19 */
|
||||
/* 51 */ Key::EQUAL, /* KeypadEqual */
|
||||
/* 52 */ Key::KP_0,
|
||||
/* 53 */ Key::KP_1,
|
||||
/* 54 */ Key::KP_2,
|
||||
/* 55 */ Key::KP_3,
|
||||
/* 56 */ Key::KP_4,
|
||||
/* 57 */ Key::KP_5,
|
||||
/* 58 */ Key::KP_6,
|
||||
/* 59 */ Key::KP_7,
|
||||
/* 5a */ Key::UNKNOWN, /* F20 */
|
||||
/* 5b */ Key::KP_8,
|
||||
/* 5c */ Key::KP_9,
|
||||
/* 5d */ Key::YEN, /* JIS Yen */
|
||||
/* 5e */ Key::UNDERSCORE, /* JIS Underscore */
|
||||
/* 5f */ Key::COMMA, /* JIS KeypadComma */
|
||||
/* 60 */ Key::F5,
|
||||
/* 61 */ Key::F6,
|
||||
/* 62 */ Key::F7,
|
||||
/* 63 */ Key::F3,
|
||||
/* 64 */ Key::F8,
|
||||
/* 65 */ Key::F9,
|
||||
/* 66 */ Key::UNKNOWN, /* JIS Eisu */
|
||||
/* 67 */ Key::F11,
|
||||
/* 68 */ Key::UNKNOWN, /* JIS Kana */
|
||||
/* 69 */ Key::F13,
|
||||
/* 6a */ Key::F16,
|
||||
/* 6b */ Key::F14,
|
||||
/* 6c */ Key::UNKNOWN,
|
||||
/* 6d */ Key::F10,
|
||||
/* 6e */ Key::MENU,
|
||||
/* 6f */ Key::F12,
|
||||
/* 70 */ Key::UNKNOWN,
|
||||
/* 71 */ Key::F15,
|
||||
/* 72 */ Key::INSERT, /* Really Help... */
|
||||
/* 73 */ Key::HOME,
|
||||
/* 74 */ Key::PAGEUP,
|
||||
/* 75 */ Key::KEY_DELETE,
|
||||
/* 76 */ Key::F4,
|
||||
/* 77 */ Key::END,
|
||||
/* 78 */ Key::F2,
|
||||
/* 79 */ Key::PAGEDOWN,
|
||||
/* 7a */ Key::F1,
|
||||
/* 7b */ Key::LEFT,
|
||||
/* 7c */ Key::RIGHT,
|
||||
/* 7d */ Key::DOWN,
|
||||
/* 7e */ Key::UP,
|
||||
/* 7f */ Key::UNKNOWN,
|
||||
};
|
||||
|
||||
// Translates a OS X keycode to a Godot keycode.
|
||||
Key KeyMappingOSX::translate_key(unsigned int key) {
|
||||
if (key >= 128) {
|
||||
return Key::UNKNOWN;
|
||||
}
|
||||
|
||||
return _osx_to_godot_table[key];
|
||||
}
|
||||
|
||||
// Translates a Godot keycode back to a OSX keycode.
|
||||
unsigned int KeyMappingOSX::unmap_key(Key key) {
|
||||
for (int i = 0; i <= 126; i++) {
|
||||
if (_osx_to_godot_table[i] == key) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return 127;
|
||||
}
|
||||
|
||||
struct _KeyCodeMap {
|
||||
UniChar kchar;
|
||||
Key kcode;
|
||||
};
|
||||
|
||||
static const _KeyCodeMap _keycodes[55] = {
|
||||
{ '`', Key::QUOTELEFT },
|
||||
{ '~', Key::ASCIITILDE },
|
||||
{ '0', Key::KEY_0 },
|
||||
{ '1', Key::KEY_1 },
|
||||
{ '2', Key::KEY_2 },
|
||||
{ '3', Key::KEY_3 },
|
||||
{ '4', Key::KEY_4 },
|
||||
{ '5', Key::KEY_5 },
|
||||
{ '6', Key::KEY_6 },
|
||||
{ '7', Key::KEY_7 },
|
||||
{ '8', Key::KEY_8 },
|
||||
{ '9', Key::KEY_9 },
|
||||
{ '-', Key::MINUS },
|
||||
{ '_', Key::UNDERSCORE },
|
||||
{ '=', Key::EQUAL },
|
||||
{ '+', Key::PLUS },
|
||||
{ 'q', Key::Q },
|
||||
{ 'w', Key::W },
|
||||
{ 'e', Key::E },
|
||||
{ 'r', Key::R },
|
||||
{ 't', Key::T },
|
||||
{ 'y', Key::Y },
|
||||
{ 'u', Key::U },
|
||||
{ 'i', Key::I },
|
||||
{ 'o', Key::O },
|
||||
{ 'p', Key::P },
|
||||
{ '[', Key::BRACELEFT },
|
||||
{ ']', Key::BRACERIGHT },
|
||||
{ '{', Key::BRACELEFT },
|
||||
{ '}', Key::BRACERIGHT },
|
||||
{ 'a', Key::A },
|
||||
{ 's', Key::S },
|
||||
{ 'd', Key::D },
|
||||
{ 'f', Key::F },
|
||||
{ 'g', Key::G },
|
||||
{ 'h', Key::H },
|
||||
{ 'j', Key::J },
|
||||
{ 'k', Key::K },
|
||||
{ 'l', Key::L },
|
||||
{ ';', Key::SEMICOLON },
|
||||
{ ':', Key::COLON },
|
||||
{ '\'', Key::APOSTROPHE },
|
||||
{ '\"', Key::QUOTEDBL },
|
||||
{ '\\', Key::BACKSLASH },
|
||||
{ '#', Key::NUMBERSIGN },
|
||||
{ 'z', Key::Z },
|
||||
{ 'x', Key::X },
|
||||
{ 'c', Key::C },
|
||||
{ 'v', Key::V },
|
||||
{ 'b', Key::B },
|
||||
{ 'n', Key::N },
|
||||
{ 'm', Key::M },
|
||||
{ ',', Key::COMMA },
|
||||
{ '.', Key::PERIOD },
|
||||
{ '/', Key::SLASH }
|
||||
};
|
||||
|
||||
// Remap key according to current keyboard layout.
|
||||
Key KeyMappingOSX::remap_key(unsigned int key, unsigned int state) {
|
||||
if (is_numpad_key(key)) {
|
||||
return translate_key(key);
|
||||
}
|
||||
|
||||
TISInputSourceRef current_keyboard = TISCopyCurrentKeyboardInputSource();
|
||||
if (!current_keyboard) {
|
||||
return translate_key(key);
|
||||
}
|
||||
|
||||
CFDataRef layout_data = (CFDataRef)TISGetInputSourceProperty(current_keyboard, kTISPropertyUnicodeKeyLayoutData);
|
||||
if (!layout_data) {
|
||||
return translate_key(key);
|
||||
}
|
||||
|
||||
const UCKeyboardLayout *keyboard_layout = (const UCKeyboardLayout *)CFDataGetBytePtr(layout_data);
|
||||
|
||||
UInt32 keys_down = 0;
|
||||
UniChar chars[4];
|
||||
UniCharCount real_length;
|
||||
|
||||
OSStatus err = UCKeyTranslate(keyboard_layout,
|
||||
key,
|
||||
kUCKeyActionDisplay,
|
||||
(state >> 8) & 0xFF,
|
||||
LMGetKbdType(),
|
||||
kUCKeyTranslateNoDeadKeysBit,
|
||||
&keys_down,
|
||||
sizeof(chars) / sizeof(chars[0]),
|
||||
&real_length,
|
||||
chars);
|
||||
|
||||
if (err != noErr) {
|
||||
return translate_key(key);
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < 55; i++) {
|
||||
if (_keycodes[i].kchar == chars[0]) {
|
||||
return _keycodes[i].kcode;
|
||||
}
|
||||
}
|
||||
return translate_key(key);
|
||||
}
|
||||
|
||||
struct _KeyCodeText {
|
||||
Key code;
|
||||
char32_t text;
|
||||
};
|
||||
|
||||
static const _KeyCodeText _native_keycodes[] = {
|
||||
/* clang-format off */
|
||||
{Key::ESCAPE ,0x001B},
|
||||
{Key::TAB ,0x0009},
|
||||
{Key::BACKTAB ,0x007F},
|
||||
{Key::BACKSPACE ,0x0008},
|
||||
{Key::ENTER ,0x000D},
|
||||
{Key::INSERT ,NSInsertFunctionKey},
|
||||
{Key::KEY_DELETE ,0x007F},
|
||||
{Key::PAUSE ,NSPauseFunctionKey},
|
||||
{Key::PRINT ,NSPrintScreenFunctionKey},
|
||||
{Key::SYSREQ ,NSSysReqFunctionKey},
|
||||
{Key::CLEAR ,NSClearLineFunctionKey},
|
||||
{Key::HOME ,0x2196},
|
||||
{Key::END ,0x2198},
|
||||
{Key::LEFT ,0x001C},
|
||||
{Key::UP ,0x001E},
|
||||
{Key::RIGHT ,0x001D},
|
||||
{Key::DOWN ,0x001F},
|
||||
{Key::PAGEUP ,0x21DE},
|
||||
{Key::PAGEDOWN ,0x21DF},
|
||||
{Key::NUMLOCK ,NSClearLineFunctionKey},
|
||||
{Key::SCROLLLOCK ,NSScrollLockFunctionKey},
|
||||
{Key::F1 ,NSF1FunctionKey},
|
||||
{Key::F2 ,NSF2FunctionKey},
|
||||
{Key::F3 ,NSF3FunctionKey},
|
||||
{Key::F4 ,NSF4FunctionKey},
|
||||
{Key::F5 ,NSF5FunctionKey},
|
||||
{Key::F6 ,NSF6FunctionKey},
|
||||
{Key::F7 ,NSF7FunctionKey},
|
||||
{Key::F8 ,NSF8FunctionKey},
|
||||
{Key::F9 ,NSF9FunctionKey},
|
||||
{Key::F10 ,NSF10FunctionKey},
|
||||
{Key::F11 ,NSF11FunctionKey},
|
||||
{Key::F12 ,NSF12FunctionKey},
|
||||
{Key::F13 ,NSF13FunctionKey},
|
||||
{Key::F14 ,NSF14FunctionKey},
|
||||
{Key::F15 ,NSF15FunctionKey},
|
||||
{Key::F16 ,NSF16FunctionKey}, //* ... NSF35FunctionKey */
|
||||
{Key::MENU ,NSMenuFunctionKey},
|
||||
{Key::HELP ,NSHelpFunctionKey},
|
||||
{Key::STOP ,NSStopFunctionKey},
|
||||
{Key::LAUNCH0 ,NSUserFunctionKey},
|
||||
{Key::SPACE ,0x0020},
|
||||
{Key::EXCLAM ,'!'},
|
||||
{Key::QUOTEDBL ,'\"'},
|
||||
{Key::NUMBERSIGN ,'#'},
|
||||
{Key::DOLLAR ,'$'},
|
||||
{Key::PERCENT ,'\%'},
|
||||
{Key::AMPERSAND ,'&'},
|
||||
{Key::APOSTROPHE ,'\''},
|
||||
{Key::PARENLEFT ,'('},
|
||||
{Key::PARENRIGHT ,')'},
|
||||
{Key::ASTERISK ,'*'},
|
||||
{Key::PLUS ,'+'},
|
||||
{Key::COMMA ,','},
|
||||
{Key::MINUS ,'-'},
|
||||
{Key::PERIOD ,'.'},
|
||||
{Key::SLASH ,'/'},
|
||||
{Key::KEY_0 ,'0'},
|
||||
{Key::KEY_1 ,'1'},
|
||||
{Key::KEY_2 ,'2'},
|
||||
{Key::KEY_3 ,'3'},
|
||||
{Key::KEY_4 ,'4'},
|
||||
{Key::KEY_5 ,'5'},
|
||||
{Key::KEY_6 ,'6'},
|
||||
{Key::KEY_7 ,'7'},
|
||||
{Key::KEY_8 ,'8'},
|
||||
{Key::KEY_9 ,'9'},
|
||||
{Key::COLON ,':'},
|
||||
{Key::SEMICOLON ,';'},
|
||||
{Key::LESS ,'<'},
|
||||
{Key::EQUAL ,'='},
|
||||
{Key::GREATER ,'>'},
|
||||
{Key::QUESTION ,'?'},
|
||||
{Key::AT ,'@'},
|
||||
{Key::A ,'a'},
|
||||
{Key::B ,'b'},
|
||||
{Key::C ,'c'},
|
||||
{Key::D ,'d'},
|
||||
{Key::E ,'e'},
|
||||
{Key::F ,'f'},
|
||||
{Key::G ,'g'},
|
||||
{Key::H ,'h'},
|
||||
{Key::I ,'i'},
|
||||
{Key::J ,'j'},
|
||||
{Key::K ,'k'},
|
||||
{Key::L ,'l'},
|
||||
{Key::M ,'m'},
|
||||
{Key::N ,'n'},
|
||||
{Key::O ,'o'},
|
||||
{Key::P ,'p'},
|
||||
{Key::Q ,'q'},
|
||||
{Key::R ,'r'},
|
||||
{Key::S ,'s'},
|
||||
{Key::T ,'t'},
|
||||
{Key::U ,'u'},
|
||||
{Key::V ,'v'},
|
||||
{Key::W ,'w'},
|
||||
{Key::X ,'x'},
|
||||
{Key::Y ,'y'},
|
||||
{Key::Z ,'z'},
|
||||
{Key::BRACKETLEFT ,'['},
|
||||
{Key::BACKSLASH ,'\\'},
|
||||
{Key::BRACKETRIGHT ,']'},
|
||||
{Key::ASCIICIRCUM ,'^'},
|
||||
{Key::UNDERSCORE ,'_'},
|
||||
{Key::QUOTELEFT ,'`'},
|
||||
{Key::BRACELEFT ,'{'},
|
||||
{Key::BAR ,'|'},
|
||||
{Key::BRACERIGHT ,'}'},
|
||||
{Key::ASCIITILDE ,'~'},
|
||||
{Key::NONE ,0x0000}
|
||||
/* clang-format on */
|
||||
};
|
||||
|
||||
String KeyMappingOSX::keycode_get_native_string(Key p_keycode) {
|
||||
const _KeyCodeText *kct = &_native_keycodes[0];
|
||||
|
||||
while (kct->text) {
|
||||
if (kct->code == p_keycode) {
|
||||
return String::chr(kct->text);
|
||||
}
|
||||
kct++;
|
||||
}
|
||||
return String();
|
||||
}
|
||||
|
||||
unsigned int KeyMappingOSX::keycode_get_native_mask(Key p_keycode) {
|
||||
unsigned int mask = 0;
|
||||
if ((p_keycode & KeyModifierMask::CTRL) != Key::NONE) {
|
||||
mask |= NSEventModifierFlagControl;
|
||||
}
|
||||
if ((p_keycode & KeyModifierMask::ALT) != Key::NONE) {
|
||||
mask |= NSEventModifierFlagOption;
|
||||
}
|
||||
if ((p_keycode & KeyModifierMask::SHIFT) != Key::NONE) {
|
||||
mask |= NSEventModifierFlagShift;
|
||||
}
|
||||
if ((p_keycode & KeyModifierMask::META) != Key::NONE) {
|
||||
mask |= NSEventModifierFlagCommand;
|
||||
}
|
||||
if ((p_keycode & KeyModifierMask::KPAD) != Key::NONE) {
|
||||
mask |= NSEventModifierFlagNumericPad;
|
||||
}
|
||||
return mask;
|
||||
}
|
||||
@ -0,0 +1,44 @@
|
||||
/*************************************************************************/
|
||||
/* osx_terminal_logger.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef OSX_TERMINAL_LOGGER_H
|
||||
#define OSX_TERMINAL_LOGGER_H
|
||||
|
||||
#ifdef OSX_ENABLED
|
||||
|
||||
#include "core/io/logger.h"
|
||||
|
||||
class OSXTerminalLogger : public StdLogger {
|
||||
public:
|
||||
virtual void log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, bool p_editor_notify = false, ErrorType p_type = ERR_ERROR) override;
|
||||
};
|
||||
|
||||
#endif // OSX_ENABLED
|
||||
#endif // OSX_TERMINAL_LOGGER_H
|
||||
@ -0,0 +1,81 @@
|
||||
/*************************************************************************/
|
||||
/* osx_terminal_logger.mm */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "osx_terminal_logger.h"
|
||||
|
||||
#ifdef OSX_ENABLED
|
||||
|
||||
#include <os/log.h>
|
||||
|
||||
void OSXTerminalLogger::log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, bool p_editor_notify, ErrorType p_type) {
|
||||
if (!should_log(true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const char *err_details;
|
||||
if (p_rationale && p_rationale[0])
|
||||
err_details = p_rationale;
|
||||
else
|
||||
err_details = p_code;
|
||||
|
||||
switch (p_type) {
|
||||
case ERR_WARNING:
|
||||
os_log_info(OS_LOG_DEFAULT,
|
||||
"WARNING: %{public}s\nat: %{public}s (%{public}s:%i)",
|
||||
err_details, p_function, p_file, p_line);
|
||||
logf_error("\E[1;33mWARNING:\E[0;93m %s\n", err_details);
|
||||
logf_error("\E[0;90m at: %s (%s:%i)\E[0m\n", p_function, p_file, p_line);
|
||||
break;
|
||||
case ERR_SCRIPT:
|
||||
os_log_error(OS_LOG_DEFAULT,
|
||||
"SCRIPT ERROR: %{public}s\nat: %{public}s (%{public}s:%i)",
|
||||
err_details, p_function, p_file, p_line);
|
||||
logf_error("\E[1;35mSCRIPT ERROR:\E[0;95m %s\n", err_details);
|
||||
logf_error("\E[0;90m at: %s (%s:%i)\E[0m\n", p_function, p_file, p_line);
|
||||
break;
|
||||
case ERR_SHADER:
|
||||
os_log_error(OS_LOG_DEFAULT,
|
||||
"SHADER ERROR: %{public}s\nat: %{public}s (%{public}s:%i)",
|
||||
err_details, p_function, p_file, p_line);
|
||||
logf_error("\E[1;36mSHADER ERROR:\E[0;96m %s\n", err_details);
|
||||
logf_error("\E[0;90m at: %s (%s:%i)\E[0m\n", p_function, p_file, p_line);
|
||||
break;
|
||||
case ERR_ERROR:
|
||||
default:
|
||||
os_log_error(OS_LOG_DEFAULT,
|
||||
"ERROR: %{public}s\nat: %{public}s (%{public}s:%i)",
|
||||
err_details, p_function, p_file, p_line);
|
||||
logf_error("\E[1;31mERROR:\E[0;91m %s\n", err_details);
|
||||
logf_error("\E[0;90m at: %s (%s:%i)\E[0m\n", p_function, p_file, p_line);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // OSX_ENABLED
|
||||
Loading…
Reference in New Issue