1b877906bSopenharmony_ci//========================================================================
2b877906bSopenharmony_ci// GLFW 3.5 macOS - www.glfw.org
3b877906bSopenharmony_ci//------------------------------------------------------------------------
4b877906bSopenharmony_ci// Copyright (c) 2009-2019 Camilla Löwy <elmindreda@glfw.org>
5b877906bSopenharmony_ci//
6b877906bSopenharmony_ci// This software is provided 'as-is', without any express or implied
7b877906bSopenharmony_ci// warranty. In no event will the authors be held liable for any damages
8b877906bSopenharmony_ci// arising from the use of this software.
9b877906bSopenharmony_ci//
10b877906bSopenharmony_ci// Permission is granted to anyone to use this software for any purpose,
11b877906bSopenharmony_ci// including commercial applications, and to alter it and redistribute it
12b877906bSopenharmony_ci// freely, subject to the following restrictions:
13b877906bSopenharmony_ci//
14b877906bSopenharmony_ci// 1. The origin of this software must not be misrepresented; you must not
15b877906bSopenharmony_ci//    claim that you wrote the original software. If you use this software
16b877906bSopenharmony_ci//    in a product, an acknowledgment in the product documentation would
17b877906bSopenharmony_ci//    be appreciated but is not required.
18b877906bSopenharmony_ci//
19b877906bSopenharmony_ci// 2. Altered source versions must be plainly marked as such, and must not
20b877906bSopenharmony_ci//    be misrepresented as being the original software.
21b877906bSopenharmony_ci//
22b877906bSopenharmony_ci// 3. This notice may not be removed or altered from any source
23b877906bSopenharmony_ci//    distribution.
24b877906bSopenharmony_ci//
25b877906bSopenharmony_ci//========================================================================
26b877906bSopenharmony_ci
27b877906bSopenharmony_ci#include "internal.h"
28b877906bSopenharmony_ci
29b877906bSopenharmony_ci#if defined(_GLFW_COCOA)
30b877906bSopenharmony_ci
31b877906bSopenharmony_ci#include <sys/param.h> // For MAXPATHLEN
32b877906bSopenharmony_ci
33b877906bSopenharmony_ci// Needed for _NSGetProgname
34b877906bSopenharmony_ci#include <crt_externs.h>
35b877906bSopenharmony_ci
36b877906bSopenharmony_ci// Change to our application bundle's resources directory, if present
37b877906bSopenharmony_ci//
38b877906bSopenharmony_cistatic void changeToResourcesDirectory(void)
39b877906bSopenharmony_ci{
40b877906bSopenharmony_ci    char resourcesPath[MAXPATHLEN];
41b877906bSopenharmony_ci
42b877906bSopenharmony_ci    CFBundleRef bundle = CFBundleGetMainBundle();
43b877906bSopenharmony_ci    if (!bundle)
44b877906bSopenharmony_ci        return;
45b877906bSopenharmony_ci
46b877906bSopenharmony_ci    CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(bundle);
47b877906bSopenharmony_ci
48b877906bSopenharmony_ci    CFStringRef last = CFURLCopyLastPathComponent(resourcesURL);
49b877906bSopenharmony_ci    if (CFStringCompare(CFSTR("Resources"), last, 0) != kCFCompareEqualTo)
50b877906bSopenharmony_ci    {
51b877906bSopenharmony_ci        CFRelease(last);
52b877906bSopenharmony_ci        CFRelease(resourcesURL);
53b877906bSopenharmony_ci        return;
54b877906bSopenharmony_ci    }
55b877906bSopenharmony_ci
56b877906bSopenharmony_ci    CFRelease(last);
57b877906bSopenharmony_ci
58b877906bSopenharmony_ci    if (!CFURLGetFileSystemRepresentation(resourcesURL,
59b877906bSopenharmony_ci                                          true,
60b877906bSopenharmony_ci                                          (UInt8*) resourcesPath,
61b877906bSopenharmony_ci                                          MAXPATHLEN))
62b877906bSopenharmony_ci    {
63b877906bSopenharmony_ci        CFRelease(resourcesURL);
64b877906bSopenharmony_ci        return;
65b877906bSopenharmony_ci    }
66b877906bSopenharmony_ci
67b877906bSopenharmony_ci    CFRelease(resourcesURL);
68b877906bSopenharmony_ci
69b877906bSopenharmony_ci    chdir(resourcesPath);
70b877906bSopenharmony_ci}
71b877906bSopenharmony_ci
72b877906bSopenharmony_ci// Set up the menu bar (manually)
73b877906bSopenharmony_ci// This is nasty, nasty stuff -- calls to undocumented semi-private APIs that
74b877906bSopenharmony_ci// could go away at any moment, lots of stuff that really should be
75b877906bSopenharmony_ci// localize(d|able), etc.  Add a nib to save us this horror.
76b877906bSopenharmony_ci//
77b877906bSopenharmony_cistatic void createMenuBar(void)
78b877906bSopenharmony_ci{
79b877906bSopenharmony_ci    NSString* appName = nil;
80b877906bSopenharmony_ci    NSDictionary* bundleInfo = [[NSBundle mainBundle] infoDictionary];
81b877906bSopenharmony_ci    NSString* nameKeys[] =
82b877906bSopenharmony_ci    {
83b877906bSopenharmony_ci        @"CFBundleDisplayName",
84b877906bSopenharmony_ci        @"CFBundleName",
85b877906bSopenharmony_ci        @"CFBundleExecutable",
86b877906bSopenharmony_ci    };
87b877906bSopenharmony_ci
88b877906bSopenharmony_ci    // Try to figure out what the calling application is called
89b877906bSopenharmony_ci
90b877906bSopenharmony_ci    for (size_t i = 0;  i < sizeof(nameKeys) / sizeof(nameKeys[0]);  i++)
91b877906bSopenharmony_ci    {
92b877906bSopenharmony_ci        id name = bundleInfo[nameKeys[i]];
93b877906bSopenharmony_ci        if (name &&
94b877906bSopenharmony_ci            [name isKindOfClass:[NSString class]] &&
95b877906bSopenharmony_ci            ![name isEqualToString:@""])
96b877906bSopenharmony_ci        {
97b877906bSopenharmony_ci            appName = name;
98b877906bSopenharmony_ci            break;
99b877906bSopenharmony_ci        }
100b877906bSopenharmony_ci    }
101b877906bSopenharmony_ci
102b877906bSopenharmony_ci    if (!appName)
103b877906bSopenharmony_ci    {
104b877906bSopenharmony_ci        char** progname = _NSGetProgname();
105b877906bSopenharmony_ci        if (progname && *progname)
106b877906bSopenharmony_ci            appName = @(*progname);
107b877906bSopenharmony_ci        else
108b877906bSopenharmony_ci            appName = @"GLFW Application";
109b877906bSopenharmony_ci    }
110b877906bSopenharmony_ci
111b877906bSopenharmony_ci    NSMenu* bar = [[NSMenu alloc] init];
112b877906bSopenharmony_ci    [NSApp setMainMenu:bar];
113b877906bSopenharmony_ci
114b877906bSopenharmony_ci    NSMenuItem* appMenuItem =
115b877906bSopenharmony_ci        [bar addItemWithTitle:@"" action:NULL keyEquivalent:@""];
116b877906bSopenharmony_ci    NSMenu* appMenu = [[NSMenu alloc] init];
117b877906bSopenharmony_ci    [appMenuItem setSubmenu:appMenu];
118b877906bSopenharmony_ci
119b877906bSopenharmony_ci    [appMenu addItemWithTitle:[NSString stringWithFormat:@"About %@", appName]
120b877906bSopenharmony_ci                       action:@selector(orderFrontStandardAboutPanel:)
121b877906bSopenharmony_ci                keyEquivalent:@""];
122b877906bSopenharmony_ci    [appMenu addItem:[NSMenuItem separatorItem]];
123b877906bSopenharmony_ci    NSMenu* servicesMenu = [[NSMenu alloc] init];
124b877906bSopenharmony_ci    [NSApp setServicesMenu:servicesMenu];
125b877906bSopenharmony_ci    [[appMenu addItemWithTitle:@"Services"
126b877906bSopenharmony_ci                       action:NULL
127b877906bSopenharmony_ci                keyEquivalent:@""] setSubmenu:servicesMenu];
128b877906bSopenharmony_ci    [servicesMenu release];
129b877906bSopenharmony_ci    [appMenu addItem:[NSMenuItem separatorItem]];
130b877906bSopenharmony_ci    [appMenu addItemWithTitle:[NSString stringWithFormat:@"Hide %@", appName]
131b877906bSopenharmony_ci                       action:@selector(hide:)
132b877906bSopenharmony_ci                keyEquivalent:@"h"];
133b877906bSopenharmony_ci    [[appMenu addItemWithTitle:@"Hide Others"
134b877906bSopenharmony_ci                       action:@selector(hideOtherApplications:)
135b877906bSopenharmony_ci                keyEquivalent:@"h"]
136b877906bSopenharmony_ci        setKeyEquivalentModifierMask:NSEventModifierFlagOption | NSEventModifierFlagCommand];
137b877906bSopenharmony_ci    [appMenu addItemWithTitle:@"Show All"
138b877906bSopenharmony_ci                       action:@selector(unhideAllApplications:)
139b877906bSopenharmony_ci                keyEquivalent:@""];
140b877906bSopenharmony_ci    [appMenu addItem:[NSMenuItem separatorItem]];
141b877906bSopenharmony_ci    [appMenu addItemWithTitle:[NSString stringWithFormat:@"Quit %@", appName]
142b877906bSopenharmony_ci                       action:@selector(terminate:)
143b877906bSopenharmony_ci                keyEquivalent:@"q"];
144b877906bSopenharmony_ci
145b877906bSopenharmony_ci    NSMenuItem* windowMenuItem =
146b877906bSopenharmony_ci        [bar addItemWithTitle:@"" action:NULL keyEquivalent:@""];
147b877906bSopenharmony_ci    [bar release];
148b877906bSopenharmony_ci    NSMenu* windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
149b877906bSopenharmony_ci    [NSApp setWindowsMenu:windowMenu];
150b877906bSopenharmony_ci    [windowMenuItem setSubmenu:windowMenu];
151b877906bSopenharmony_ci
152b877906bSopenharmony_ci    [windowMenu addItemWithTitle:@"Minimize"
153b877906bSopenharmony_ci                          action:@selector(performMiniaturize:)
154b877906bSopenharmony_ci                   keyEquivalent:@"m"];
155b877906bSopenharmony_ci    [windowMenu addItemWithTitle:@"Zoom"
156b877906bSopenharmony_ci                          action:@selector(performZoom:)
157b877906bSopenharmony_ci                   keyEquivalent:@""];
158b877906bSopenharmony_ci    [windowMenu addItem:[NSMenuItem separatorItem]];
159b877906bSopenharmony_ci    [windowMenu addItemWithTitle:@"Bring All to Front"
160b877906bSopenharmony_ci                          action:@selector(arrangeInFront:)
161b877906bSopenharmony_ci                   keyEquivalent:@""];
162b877906bSopenharmony_ci
163b877906bSopenharmony_ci    // TODO: Make this appear at the bottom of the menu (for consistency)
164b877906bSopenharmony_ci    [windowMenu addItem:[NSMenuItem separatorItem]];
165b877906bSopenharmony_ci    [[windowMenu addItemWithTitle:@"Enter Full Screen"
166b877906bSopenharmony_ci                           action:@selector(toggleFullScreen:)
167b877906bSopenharmony_ci                    keyEquivalent:@"f"]
168b877906bSopenharmony_ci     setKeyEquivalentModifierMask:NSEventModifierFlagControl | NSEventModifierFlagCommand];
169b877906bSopenharmony_ci
170b877906bSopenharmony_ci    // Prior to Snow Leopard, we need to use this oddly-named semi-private API
171b877906bSopenharmony_ci    // to get the application menu working properly.
172b877906bSopenharmony_ci    SEL setAppleMenuSelector = NSSelectorFromString(@"setAppleMenu:");
173b877906bSopenharmony_ci    [NSApp performSelector:setAppleMenuSelector withObject:appMenu];
174b877906bSopenharmony_ci}
175b877906bSopenharmony_ci
176b877906bSopenharmony_ci// Create key code translation tables
177b877906bSopenharmony_ci//
178b877906bSopenharmony_cistatic void createKeyTables(void)
179b877906bSopenharmony_ci{
180b877906bSopenharmony_ci    memset(_glfw.ns.keycodes, -1, sizeof(_glfw.ns.keycodes));
181b877906bSopenharmony_ci    memset(_glfw.ns.scancodes, -1, sizeof(_glfw.ns.scancodes));
182b877906bSopenharmony_ci
183b877906bSopenharmony_ci    _glfw.ns.keycodes[0x1D] = GLFW_KEY_0;
184b877906bSopenharmony_ci    _glfw.ns.keycodes[0x12] = GLFW_KEY_1;
185b877906bSopenharmony_ci    _glfw.ns.keycodes[0x13] = GLFW_KEY_2;
186b877906bSopenharmony_ci    _glfw.ns.keycodes[0x14] = GLFW_KEY_3;
187b877906bSopenharmony_ci    _glfw.ns.keycodes[0x15] = GLFW_KEY_4;
188b877906bSopenharmony_ci    _glfw.ns.keycodes[0x17] = GLFW_KEY_5;
189b877906bSopenharmony_ci    _glfw.ns.keycodes[0x16] = GLFW_KEY_6;
190b877906bSopenharmony_ci    _glfw.ns.keycodes[0x1A] = GLFW_KEY_7;
191b877906bSopenharmony_ci    _glfw.ns.keycodes[0x1C] = GLFW_KEY_8;
192b877906bSopenharmony_ci    _glfw.ns.keycodes[0x19] = GLFW_KEY_9;
193b877906bSopenharmony_ci    _glfw.ns.keycodes[0x00] = GLFW_KEY_A;
194b877906bSopenharmony_ci    _glfw.ns.keycodes[0x0B] = GLFW_KEY_B;
195b877906bSopenharmony_ci    _glfw.ns.keycodes[0x08] = GLFW_KEY_C;
196b877906bSopenharmony_ci    _glfw.ns.keycodes[0x02] = GLFW_KEY_D;
197b877906bSopenharmony_ci    _glfw.ns.keycodes[0x0E] = GLFW_KEY_E;
198b877906bSopenharmony_ci    _glfw.ns.keycodes[0x03] = GLFW_KEY_F;
199b877906bSopenharmony_ci    _glfw.ns.keycodes[0x05] = GLFW_KEY_G;
200b877906bSopenharmony_ci    _glfw.ns.keycodes[0x04] = GLFW_KEY_H;
201b877906bSopenharmony_ci    _glfw.ns.keycodes[0x22] = GLFW_KEY_I;
202b877906bSopenharmony_ci    _glfw.ns.keycodes[0x26] = GLFW_KEY_J;
203b877906bSopenharmony_ci    _glfw.ns.keycodes[0x28] = GLFW_KEY_K;
204b877906bSopenharmony_ci    _glfw.ns.keycodes[0x25] = GLFW_KEY_L;
205b877906bSopenharmony_ci    _glfw.ns.keycodes[0x2E] = GLFW_KEY_M;
206b877906bSopenharmony_ci    _glfw.ns.keycodes[0x2D] = GLFW_KEY_N;
207b877906bSopenharmony_ci    _glfw.ns.keycodes[0x1F] = GLFW_KEY_O;
208b877906bSopenharmony_ci    _glfw.ns.keycodes[0x23] = GLFW_KEY_P;
209b877906bSopenharmony_ci    _glfw.ns.keycodes[0x0C] = GLFW_KEY_Q;
210b877906bSopenharmony_ci    _glfw.ns.keycodes[0x0F] = GLFW_KEY_R;
211b877906bSopenharmony_ci    _glfw.ns.keycodes[0x01] = GLFW_KEY_S;
212b877906bSopenharmony_ci    _glfw.ns.keycodes[0x11] = GLFW_KEY_T;
213b877906bSopenharmony_ci    _glfw.ns.keycodes[0x20] = GLFW_KEY_U;
214b877906bSopenharmony_ci    _glfw.ns.keycodes[0x09] = GLFW_KEY_V;
215b877906bSopenharmony_ci    _glfw.ns.keycodes[0x0D] = GLFW_KEY_W;
216b877906bSopenharmony_ci    _glfw.ns.keycodes[0x07] = GLFW_KEY_X;
217b877906bSopenharmony_ci    _glfw.ns.keycodes[0x10] = GLFW_KEY_Y;
218b877906bSopenharmony_ci    _glfw.ns.keycodes[0x06] = GLFW_KEY_Z;
219b877906bSopenharmony_ci
220b877906bSopenharmony_ci    _glfw.ns.keycodes[0x27] = GLFW_KEY_APOSTROPHE;
221b877906bSopenharmony_ci    _glfw.ns.keycodes[0x2A] = GLFW_KEY_BACKSLASH;
222b877906bSopenharmony_ci    _glfw.ns.keycodes[0x2B] = GLFW_KEY_COMMA;
223b877906bSopenharmony_ci    _glfw.ns.keycodes[0x18] = GLFW_KEY_EQUAL;
224b877906bSopenharmony_ci    _glfw.ns.keycodes[0x32] = GLFW_KEY_GRAVE_ACCENT;
225b877906bSopenharmony_ci    _glfw.ns.keycodes[0x21] = GLFW_KEY_LEFT_BRACKET;
226b877906bSopenharmony_ci    _glfw.ns.keycodes[0x1B] = GLFW_KEY_MINUS;
227b877906bSopenharmony_ci    _glfw.ns.keycodes[0x2F] = GLFW_KEY_PERIOD;
228b877906bSopenharmony_ci    _glfw.ns.keycodes[0x1E] = GLFW_KEY_RIGHT_BRACKET;
229b877906bSopenharmony_ci    _glfw.ns.keycodes[0x29] = GLFW_KEY_SEMICOLON;
230b877906bSopenharmony_ci    _glfw.ns.keycodes[0x2C] = GLFW_KEY_SLASH;
231b877906bSopenharmony_ci    _glfw.ns.keycodes[0x0A] = GLFW_KEY_WORLD_1;
232b877906bSopenharmony_ci
233b877906bSopenharmony_ci    _glfw.ns.keycodes[0x33] = GLFW_KEY_BACKSPACE;
234b877906bSopenharmony_ci    _glfw.ns.keycodes[0x39] = GLFW_KEY_CAPS_LOCK;
235b877906bSopenharmony_ci    _glfw.ns.keycodes[0x75] = GLFW_KEY_DELETE;
236b877906bSopenharmony_ci    _glfw.ns.keycodes[0x7D] = GLFW_KEY_DOWN;
237b877906bSopenharmony_ci    _glfw.ns.keycodes[0x77] = GLFW_KEY_END;
238b877906bSopenharmony_ci    _glfw.ns.keycodes[0x24] = GLFW_KEY_ENTER;
239b877906bSopenharmony_ci    _glfw.ns.keycodes[0x35] = GLFW_KEY_ESCAPE;
240b877906bSopenharmony_ci    _glfw.ns.keycodes[0x7A] = GLFW_KEY_F1;
241b877906bSopenharmony_ci    _glfw.ns.keycodes[0x78] = GLFW_KEY_F2;
242b877906bSopenharmony_ci    _glfw.ns.keycodes[0x63] = GLFW_KEY_F3;
243b877906bSopenharmony_ci    _glfw.ns.keycodes[0x76] = GLFW_KEY_F4;
244b877906bSopenharmony_ci    _glfw.ns.keycodes[0x60] = GLFW_KEY_F5;
245b877906bSopenharmony_ci    _glfw.ns.keycodes[0x61] = GLFW_KEY_F6;
246b877906bSopenharmony_ci    _glfw.ns.keycodes[0x62] = GLFW_KEY_F7;
247b877906bSopenharmony_ci    _glfw.ns.keycodes[0x64] = GLFW_KEY_F8;
248b877906bSopenharmony_ci    _glfw.ns.keycodes[0x65] = GLFW_KEY_F9;
249b877906bSopenharmony_ci    _glfw.ns.keycodes[0x6D] = GLFW_KEY_F10;
250b877906bSopenharmony_ci    _glfw.ns.keycodes[0x67] = GLFW_KEY_F11;
251b877906bSopenharmony_ci    _glfw.ns.keycodes[0x6F] = GLFW_KEY_F12;
252b877906bSopenharmony_ci    _glfw.ns.keycodes[0x69] = GLFW_KEY_PRINT_SCREEN;
253b877906bSopenharmony_ci    _glfw.ns.keycodes[0x6B] = GLFW_KEY_F14;
254b877906bSopenharmony_ci    _glfw.ns.keycodes[0x71] = GLFW_KEY_F15;
255b877906bSopenharmony_ci    _glfw.ns.keycodes[0x6A] = GLFW_KEY_F16;
256b877906bSopenharmony_ci    _glfw.ns.keycodes[0x40] = GLFW_KEY_F17;
257b877906bSopenharmony_ci    _glfw.ns.keycodes[0x4F] = GLFW_KEY_F18;
258b877906bSopenharmony_ci    _glfw.ns.keycodes[0x50] = GLFW_KEY_F19;
259b877906bSopenharmony_ci    _glfw.ns.keycodes[0x5A] = GLFW_KEY_F20;
260b877906bSopenharmony_ci    _glfw.ns.keycodes[0x73] = GLFW_KEY_HOME;
261b877906bSopenharmony_ci    _glfw.ns.keycodes[0x72] = GLFW_KEY_INSERT;
262b877906bSopenharmony_ci    _glfw.ns.keycodes[0x7B] = GLFW_KEY_LEFT;
263b877906bSopenharmony_ci    _glfw.ns.keycodes[0x3A] = GLFW_KEY_LEFT_ALT;
264b877906bSopenharmony_ci    _glfw.ns.keycodes[0x3B] = GLFW_KEY_LEFT_CONTROL;
265b877906bSopenharmony_ci    _glfw.ns.keycodes[0x38] = GLFW_KEY_LEFT_SHIFT;
266b877906bSopenharmony_ci    _glfw.ns.keycodes[0x37] = GLFW_KEY_LEFT_SUPER;
267b877906bSopenharmony_ci    _glfw.ns.keycodes[0x6E] = GLFW_KEY_MENU;
268b877906bSopenharmony_ci    _glfw.ns.keycodes[0x47] = GLFW_KEY_NUM_LOCK;
269b877906bSopenharmony_ci    _glfw.ns.keycodes[0x79] = GLFW_KEY_PAGE_DOWN;
270b877906bSopenharmony_ci    _glfw.ns.keycodes[0x74] = GLFW_KEY_PAGE_UP;
271b877906bSopenharmony_ci    _glfw.ns.keycodes[0x7C] = GLFW_KEY_RIGHT;
272b877906bSopenharmony_ci    _glfw.ns.keycodes[0x3D] = GLFW_KEY_RIGHT_ALT;
273b877906bSopenharmony_ci    _glfw.ns.keycodes[0x3E] = GLFW_KEY_RIGHT_CONTROL;
274b877906bSopenharmony_ci    _glfw.ns.keycodes[0x3C] = GLFW_KEY_RIGHT_SHIFT;
275b877906bSopenharmony_ci    _glfw.ns.keycodes[0x36] = GLFW_KEY_RIGHT_SUPER;
276b877906bSopenharmony_ci    _glfw.ns.keycodes[0x31] = GLFW_KEY_SPACE;
277b877906bSopenharmony_ci    _glfw.ns.keycodes[0x30] = GLFW_KEY_TAB;
278b877906bSopenharmony_ci    _glfw.ns.keycodes[0x7E] = GLFW_KEY_UP;
279b877906bSopenharmony_ci
280b877906bSopenharmony_ci    _glfw.ns.keycodes[0x52] = GLFW_KEY_KP_0;
281b877906bSopenharmony_ci    _glfw.ns.keycodes[0x53] = GLFW_KEY_KP_1;
282b877906bSopenharmony_ci    _glfw.ns.keycodes[0x54] = GLFW_KEY_KP_2;
283b877906bSopenharmony_ci    _glfw.ns.keycodes[0x55] = GLFW_KEY_KP_3;
284b877906bSopenharmony_ci    _glfw.ns.keycodes[0x56] = GLFW_KEY_KP_4;
285b877906bSopenharmony_ci    _glfw.ns.keycodes[0x57] = GLFW_KEY_KP_5;
286b877906bSopenharmony_ci    _glfw.ns.keycodes[0x58] = GLFW_KEY_KP_6;
287b877906bSopenharmony_ci    _glfw.ns.keycodes[0x59] = GLFW_KEY_KP_7;
288b877906bSopenharmony_ci    _glfw.ns.keycodes[0x5B] = GLFW_KEY_KP_8;
289b877906bSopenharmony_ci    _glfw.ns.keycodes[0x5C] = GLFW_KEY_KP_9;
290b877906bSopenharmony_ci    _glfw.ns.keycodes[0x45] = GLFW_KEY_KP_ADD;
291b877906bSopenharmony_ci    _glfw.ns.keycodes[0x41] = GLFW_KEY_KP_DECIMAL;
292b877906bSopenharmony_ci    _glfw.ns.keycodes[0x4B] = GLFW_KEY_KP_DIVIDE;
293b877906bSopenharmony_ci    _glfw.ns.keycodes[0x4C] = GLFW_KEY_KP_ENTER;
294b877906bSopenharmony_ci    _glfw.ns.keycodes[0x51] = GLFW_KEY_KP_EQUAL;
295b877906bSopenharmony_ci    _glfw.ns.keycodes[0x43] = GLFW_KEY_KP_MULTIPLY;
296b877906bSopenharmony_ci    _glfw.ns.keycodes[0x4E] = GLFW_KEY_KP_SUBTRACT;
297b877906bSopenharmony_ci
298b877906bSopenharmony_ci    for (int scancode = 0;  scancode < 256;  scancode++)
299b877906bSopenharmony_ci    {
300b877906bSopenharmony_ci        // Store the reverse translation for faster key name lookup
301b877906bSopenharmony_ci        if (_glfw.ns.keycodes[scancode] >= 0)
302b877906bSopenharmony_ci            _glfw.ns.scancodes[_glfw.ns.keycodes[scancode]] = scancode;
303b877906bSopenharmony_ci    }
304b877906bSopenharmony_ci}
305b877906bSopenharmony_ci
306b877906bSopenharmony_ci// Retrieve Unicode data for the current keyboard layout
307b877906bSopenharmony_ci//
308b877906bSopenharmony_cistatic GLFWbool updateUnicodeData(void)
309b877906bSopenharmony_ci{
310b877906bSopenharmony_ci    if (_glfw.ns.inputSource)
311b877906bSopenharmony_ci    {
312b877906bSopenharmony_ci        CFRelease(_glfw.ns.inputSource);
313b877906bSopenharmony_ci        _glfw.ns.inputSource = NULL;
314b877906bSopenharmony_ci        _glfw.ns.unicodeData = nil;
315b877906bSopenharmony_ci    }
316b877906bSopenharmony_ci
317b877906bSopenharmony_ci    _glfw.ns.inputSource = TISCopyCurrentKeyboardLayoutInputSource();
318b877906bSopenharmony_ci    if (!_glfw.ns.inputSource)
319b877906bSopenharmony_ci    {
320b877906bSopenharmony_ci        _glfwInputError(GLFW_PLATFORM_ERROR,
321b877906bSopenharmony_ci                        "Cocoa: Failed to retrieve keyboard layout input source");
322b877906bSopenharmony_ci        return GLFW_FALSE;
323b877906bSopenharmony_ci    }
324b877906bSopenharmony_ci
325b877906bSopenharmony_ci    _glfw.ns.unicodeData =
326b877906bSopenharmony_ci        TISGetInputSourceProperty(_glfw.ns.inputSource,
327b877906bSopenharmony_ci                                  kTISPropertyUnicodeKeyLayoutData);
328b877906bSopenharmony_ci    if (!_glfw.ns.unicodeData)
329b877906bSopenharmony_ci    {
330b877906bSopenharmony_ci        _glfwInputError(GLFW_PLATFORM_ERROR,
331b877906bSopenharmony_ci                        "Cocoa: Failed to retrieve keyboard layout Unicode data");
332b877906bSopenharmony_ci        return GLFW_FALSE;
333b877906bSopenharmony_ci    }
334b877906bSopenharmony_ci
335b877906bSopenharmony_ci    return GLFW_TRUE;
336b877906bSopenharmony_ci}
337b877906bSopenharmony_ci
338b877906bSopenharmony_ci// Load HIToolbox.framework and the TIS symbols we need from it
339b877906bSopenharmony_ci//
340b877906bSopenharmony_cistatic GLFWbool initializeTIS(void)
341b877906bSopenharmony_ci{
342b877906bSopenharmony_ci    // This works only because Cocoa has already loaded it properly
343b877906bSopenharmony_ci    _glfw.ns.tis.bundle =
344b877906bSopenharmony_ci        CFBundleGetBundleWithIdentifier(CFSTR("com.apple.HIToolbox"));
345b877906bSopenharmony_ci    if (!_glfw.ns.tis.bundle)
346b877906bSopenharmony_ci    {
347b877906bSopenharmony_ci        _glfwInputError(GLFW_PLATFORM_ERROR,
348b877906bSopenharmony_ci                        "Cocoa: Failed to load HIToolbox.framework");
349b877906bSopenharmony_ci        return GLFW_FALSE;
350b877906bSopenharmony_ci    }
351b877906bSopenharmony_ci
352b877906bSopenharmony_ci    CFStringRef* kPropertyUnicodeKeyLayoutData =
353b877906bSopenharmony_ci        CFBundleGetDataPointerForName(_glfw.ns.tis.bundle,
354b877906bSopenharmony_ci                                      CFSTR("kTISPropertyUnicodeKeyLayoutData"));
355b877906bSopenharmony_ci    _glfw.ns.tis.CopyCurrentKeyboardLayoutInputSource =
356b877906bSopenharmony_ci        CFBundleGetFunctionPointerForName(_glfw.ns.tis.bundle,
357b877906bSopenharmony_ci                                          CFSTR("TISCopyCurrentKeyboardLayoutInputSource"));
358b877906bSopenharmony_ci    _glfw.ns.tis.GetInputSourceProperty =
359b877906bSopenharmony_ci        CFBundleGetFunctionPointerForName(_glfw.ns.tis.bundle,
360b877906bSopenharmony_ci                                          CFSTR("TISGetInputSourceProperty"));
361b877906bSopenharmony_ci    _glfw.ns.tis.GetKbdType =
362b877906bSopenharmony_ci        CFBundleGetFunctionPointerForName(_glfw.ns.tis.bundle,
363b877906bSopenharmony_ci                                          CFSTR("LMGetKbdType"));
364b877906bSopenharmony_ci
365b877906bSopenharmony_ci    if (!kPropertyUnicodeKeyLayoutData ||
366b877906bSopenharmony_ci        !TISCopyCurrentKeyboardLayoutInputSource ||
367b877906bSopenharmony_ci        !TISGetInputSourceProperty ||
368b877906bSopenharmony_ci        !LMGetKbdType)
369b877906bSopenharmony_ci    {
370b877906bSopenharmony_ci        _glfwInputError(GLFW_PLATFORM_ERROR,
371b877906bSopenharmony_ci                        "Cocoa: Failed to load TIS API symbols");
372b877906bSopenharmony_ci        return GLFW_FALSE;
373b877906bSopenharmony_ci    }
374b877906bSopenharmony_ci
375b877906bSopenharmony_ci    _glfw.ns.tis.kPropertyUnicodeKeyLayoutData =
376b877906bSopenharmony_ci        *kPropertyUnicodeKeyLayoutData;
377b877906bSopenharmony_ci
378b877906bSopenharmony_ci    return updateUnicodeData();
379b877906bSopenharmony_ci}
380b877906bSopenharmony_ci
381b877906bSopenharmony_ci@interface GLFWHelper : NSObject
382b877906bSopenharmony_ci@end
383b877906bSopenharmony_ci
384b877906bSopenharmony_ci@implementation GLFWHelper
385b877906bSopenharmony_ci
386b877906bSopenharmony_ci- (void)selectedKeyboardInputSourceChanged:(NSObject* )object
387b877906bSopenharmony_ci{
388b877906bSopenharmony_ci    updateUnicodeData();
389b877906bSopenharmony_ci}
390b877906bSopenharmony_ci
391b877906bSopenharmony_ci- (void)doNothing:(id)object
392b877906bSopenharmony_ci{
393b877906bSopenharmony_ci}
394b877906bSopenharmony_ci
395b877906bSopenharmony_ci@end // GLFWHelper
396b877906bSopenharmony_ci
397b877906bSopenharmony_ci@interface GLFWApplicationDelegate : NSObject <NSApplicationDelegate>
398b877906bSopenharmony_ci@end
399b877906bSopenharmony_ci
400b877906bSopenharmony_ci@implementation GLFWApplicationDelegate
401b877906bSopenharmony_ci
402b877906bSopenharmony_ci- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
403b877906bSopenharmony_ci{
404b877906bSopenharmony_ci    for (_GLFWwindow* window = _glfw.windowListHead;  window;  window = window->next)
405b877906bSopenharmony_ci        _glfwInputWindowCloseRequest(window);
406b877906bSopenharmony_ci
407b877906bSopenharmony_ci    return NSTerminateCancel;
408b877906bSopenharmony_ci}
409b877906bSopenharmony_ci
410b877906bSopenharmony_ci- (void)applicationDidChangeScreenParameters:(NSNotification *) notification
411b877906bSopenharmony_ci{
412b877906bSopenharmony_ci    for (_GLFWwindow* window = _glfw.windowListHead;  window;  window = window->next)
413b877906bSopenharmony_ci    {
414b877906bSopenharmony_ci        if (window->context.client != GLFW_NO_API)
415b877906bSopenharmony_ci            [window->context.nsgl.object update];
416b877906bSopenharmony_ci    }
417b877906bSopenharmony_ci
418b877906bSopenharmony_ci    _glfwPollMonitorsCocoa();
419b877906bSopenharmony_ci}
420b877906bSopenharmony_ci
421b877906bSopenharmony_ci- (void)applicationWillFinishLaunching:(NSNotification *)notification
422b877906bSopenharmony_ci{
423b877906bSopenharmony_ci    if (_glfw.hints.init.ns.menubar)
424b877906bSopenharmony_ci    {
425b877906bSopenharmony_ci        // Menu bar setup must go between sharedApplication and finishLaunching
426b877906bSopenharmony_ci        // in order to properly emulate the behavior of NSApplicationMain
427b877906bSopenharmony_ci
428b877906bSopenharmony_ci        if ([[NSBundle mainBundle] pathForResource:@"MainMenu" ofType:@"nib"])
429b877906bSopenharmony_ci        {
430b877906bSopenharmony_ci            [[NSBundle mainBundle] loadNibNamed:@"MainMenu"
431b877906bSopenharmony_ci                                          owner:NSApp
432b877906bSopenharmony_ci                                topLevelObjects:&_glfw.ns.nibObjects];
433b877906bSopenharmony_ci        }
434b877906bSopenharmony_ci        else
435b877906bSopenharmony_ci            createMenuBar();
436b877906bSopenharmony_ci    }
437b877906bSopenharmony_ci}
438b877906bSopenharmony_ci
439b877906bSopenharmony_ci- (void)applicationDidFinishLaunching:(NSNotification *)notification
440b877906bSopenharmony_ci{
441b877906bSopenharmony_ci    _glfwPostEmptyEventCocoa();
442b877906bSopenharmony_ci    [NSApp stop:nil];
443b877906bSopenharmony_ci}
444b877906bSopenharmony_ci
445b877906bSopenharmony_ci- (void)applicationDidHide:(NSNotification *)notification
446b877906bSopenharmony_ci{
447b877906bSopenharmony_ci    for (int i = 0;  i < _glfw.monitorCount;  i++)
448b877906bSopenharmony_ci        _glfwRestoreVideoModeCocoa(_glfw.monitors[i]);
449b877906bSopenharmony_ci}
450b877906bSopenharmony_ci
451b877906bSopenharmony_ci@end // GLFWApplicationDelegate
452b877906bSopenharmony_ci
453b877906bSopenharmony_ci
454b877906bSopenharmony_ci//////////////////////////////////////////////////////////////////////////
455b877906bSopenharmony_ci//////                       GLFW internal API                      //////
456b877906bSopenharmony_ci//////////////////////////////////////////////////////////////////////////
457b877906bSopenharmony_ci
458b877906bSopenharmony_civoid* _glfwLoadLocalVulkanLoaderCocoa(void)
459b877906bSopenharmony_ci{
460b877906bSopenharmony_ci    CFBundleRef bundle = CFBundleGetMainBundle();
461b877906bSopenharmony_ci    if (!bundle)
462b877906bSopenharmony_ci        return NULL;
463b877906bSopenharmony_ci
464b877906bSopenharmony_ci    CFURLRef frameworksUrl = CFBundleCopyPrivateFrameworksURL(bundle);
465b877906bSopenharmony_ci    if (!frameworksUrl)
466b877906bSopenharmony_ci        return NULL;
467b877906bSopenharmony_ci
468b877906bSopenharmony_ci    CFURLRef loaderUrl = CFURLCreateCopyAppendingPathComponent(
469b877906bSopenharmony_ci        kCFAllocatorDefault, frameworksUrl, CFSTR("libvulkan.1.dylib"), false);
470b877906bSopenharmony_ci    if (!loaderUrl)
471b877906bSopenharmony_ci    {
472b877906bSopenharmony_ci        CFRelease(frameworksUrl);
473b877906bSopenharmony_ci        return NULL;
474b877906bSopenharmony_ci    }
475b877906bSopenharmony_ci
476b877906bSopenharmony_ci    char path[PATH_MAX];
477b877906bSopenharmony_ci    void* handle = NULL;
478b877906bSopenharmony_ci
479b877906bSopenharmony_ci    if (CFURLGetFileSystemRepresentation(loaderUrl, true, (UInt8*) path, sizeof(path) - 1))
480b877906bSopenharmony_ci        handle = _glfwPlatformLoadModule(path);
481b877906bSopenharmony_ci
482b877906bSopenharmony_ci    CFRelease(loaderUrl);
483b877906bSopenharmony_ci    CFRelease(frameworksUrl);
484b877906bSopenharmony_ci    return handle;
485b877906bSopenharmony_ci}
486b877906bSopenharmony_ci
487b877906bSopenharmony_ci
488b877906bSopenharmony_ci//////////////////////////////////////////////////////////////////////////
489b877906bSopenharmony_ci//////                       GLFW platform API                      //////
490b877906bSopenharmony_ci//////////////////////////////////////////////////////////////////////////
491b877906bSopenharmony_ci
492b877906bSopenharmony_ciGLFWbool _glfwConnectCocoa(int platformID, _GLFWplatform* platform)
493b877906bSopenharmony_ci{
494b877906bSopenharmony_ci    const _GLFWplatform cocoa =
495b877906bSopenharmony_ci    {
496b877906bSopenharmony_ci        .platformID = GLFW_PLATFORM_COCOA,
497b877906bSopenharmony_ci        .init = _glfwInitCocoa,
498b877906bSopenharmony_ci        .terminate = _glfwTerminateCocoa,
499b877906bSopenharmony_ci        .getCursorPos = _glfwGetCursorPosCocoa,
500b877906bSopenharmony_ci        .setCursorPos = _glfwSetCursorPosCocoa,
501b877906bSopenharmony_ci        .setCursorMode = _glfwSetCursorModeCocoa,
502b877906bSopenharmony_ci        .setRawMouseMotion = _glfwSetRawMouseMotionCocoa,
503b877906bSopenharmony_ci        .rawMouseMotionSupported = _glfwRawMouseMotionSupportedCocoa,
504b877906bSopenharmony_ci        .createCursor = _glfwCreateCursorCocoa,
505b877906bSopenharmony_ci        .createStandardCursor = _glfwCreateStandardCursorCocoa,
506b877906bSopenharmony_ci        .destroyCursor = _glfwDestroyCursorCocoa,
507b877906bSopenharmony_ci        .setCursor = _glfwSetCursorCocoa,
508b877906bSopenharmony_ci        .getScancodeName = _glfwGetScancodeNameCocoa,
509b877906bSopenharmony_ci        .getKeyScancode = _glfwGetKeyScancodeCocoa,
510b877906bSopenharmony_ci        .setClipboardString = _glfwSetClipboardStringCocoa,
511b877906bSopenharmony_ci        .getClipboardString = _glfwGetClipboardStringCocoa,
512b877906bSopenharmony_ci        .initJoysticks = _glfwInitJoysticksCocoa,
513b877906bSopenharmony_ci        .terminateJoysticks = _glfwTerminateJoysticksCocoa,
514b877906bSopenharmony_ci        .pollJoystick = _glfwPollJoystickCocoa,
515b877906bSopenharmony_ci        .getMappingName = _glfwGetMappingNameCocoa,
516b877906bSopenharmony_ci        .updateGamepadGUID = _glfwUpdateGamepadGUIDCocoa,
517b877906bSopenharmony_ci        .freeMonitor = _glfwFreeMonitorCocoa,
518b877906bSopenharmony_ci        .getMonitorPos = _glfwGetMonitorPosCocoa,
519b877906bSopenharmony_ci        .getMonitorContentScale = _glfwGetMonitorContentScaleCocoa,
520b877906bSopenharmony_ci        .getMonitorWorkarea = _glfwGetMonitorWorkareaCocoa,
521b877906bSopenharmony_ci        .getVideoModes = _glfwGetVideoModesCocoa,
522b877906bSopenharmony_ci        .getVideoMode = _glfwGetVideoModeCocoa,
523b877906bSopenharmony_ci        .getGammaRamp = _glfwGetGammaRampCocoa,
524b877906bSopenharmony_ci        .setGammaRamp = _glfwSetGammaRampCocoa,
525b877906bSopenharmony_ci        .createWindow = _glfwCreateWindowCocoa,
526b877906bSopenharmony_ci        .destroyWindow = _glfwDestroyWindowCocoa,
527b877906bSopenharmony_ci        .setWindowTitle = _glfwSetWindowTitleCocoa,
528b877906bSopenharmony_ci        .setWindowIcon = _glfwSetWindowIconCocoa,
529b877906bSopenharmony_ci        .getWindowPos = _glfwGetWindowPosCocoa,
530b877906bSopenharmony_ci        .setWindowPos = _glfwSetWindowPosCocoa,
531b877906bSopenharmony_ci        .getWindowSize = _glfwGetWindowSizeCocoa,
532b877906bSopenharmony_ci        .setWindowSize = _glfwSetWindowSizeCocoa,
533b877906bSopenharmony_ci        .setWindowSizeLimits = _glfwSetWindowSizeLimitsCocoa,
534b877906bSopenharmony_ci        .setWindowAspectRatio = _glfwSetWindowAspectRatioCocoa,
535b877906bSopenharmony_ci        .getFramebufferSize = _glfwGetFramebufferSizeCocoa,
536b877906bSopenharmony_ci        .getWindowFrameSize = _glfwGetWindowFrameSizeCocoa,
537b877906bSopenharmony_ci        .getWindowContentScale = _glfwGetWindowContentScaleCocoa,
538b877906bSopenharmony_ci        .iconifyWindow = _glfwIconifyWindowCocoa,
539b877906bSopenharmony_ci        .restoreWindow = _glfwRestoreWindowCocoa,
540b877906bSopenharmony_ci        .maximizeWindow = _glfwMaximizeWindowCocoa,
541b877906bSopenharmony_ci        .showWindow = _glfwShowWindowCocoa,
542b877906bSopenharmony_ci        .hideWindow = _glfwHideWindowCocoa,
543b877906bSopenharmony_ci        .requestWindowAttention = _glfwRequestWindowAttentionCocoa,
544b877906bSopenharmony_ci        .focusWindow = _glfwFocusWindowCocoa,
545b877906bSopenharmony_ci        .setWindowMonitor = _glfwSetWindowMonitorCocoa,
546b877906bSopenharmony_ci        .windowFocused = _glfwWindowFocusedCocoa,
547b877906bSopenharmony_ci        .windowIconified = _glfwWindowIconifiedCocoa,
548b877906bSopenharmony_ci        .windowVisible = _glfwWindowVisibleCocoa,
549b877906bSopenharmony_ci        .windowMaximized = _glfwWindowMaximizedCocoa,
550b877906bSopenharmony_ci        .windowHovered = _glfwWindowHoveredCocoa,
551b877906bSopenharmony_ci        .framebufferTransparent = _glfwFramebufferTransparentCocoa,
552b877906bSopenharmony_ci        .getWindowOpacity = _glfwGetWindowOpacityCocoa,
553b877906bSopenharmony_ci        .setWindowResizable = _glfwSetWindowResizableCocoa,
554b877906bSopenharmony_ci        .setWindowDecorated = _glfwSetWindowDecoratedCocoa,
555b877906bSopenharmony_ci        .setWindowFloating = _glfwSetWindowFloatingCocoa,
556b877906bSopenharmony_ci        .setWindowOpacity = _glfwSetWindowOpacityCocoa,
557b877906bSopenharmony_ci        .setWindowMousePassthrough = _glfwSetWindowMousePassthroughCocoa,
558b877906bSopenharmony_ci        .pollEvents = _glfwPollEventsCocoa,
559b877906bSopenharmony_ci        .waitEvents = _glfwWaitEventsCocoa,
560b877906bSopenharmony_ci        .waitEventsTimeout = _glfwWaitEventsTimeoutCocoa,
561b877906bSopenharmony_ci        .postEmptyEvent = _glfwPostEmptyEventCocoa,
562b877906bSopenharmony_ci        .getEGLPlatform = _glfwGetEGLPlatformCocoa,
563b877906bSopenharmony_ci        .getEGLNativeDisplay = _glfwGetEGLNativeDisplayCocoa,
564b877906bSopenharmony_ci        .getEGLNativeWindow = _glfwGetEGLNativeWindowCocoa,
565b877906bSopenharmony_ci        .getRequiredInstanceExtensions = _glfwGetRequiredInstanceExtensionsCocoa,
566b877906bSopenharmony_ci        .getPhysicalDevicePresentationSupport = _glfwGetPhysicalDevicePresentationSupportCocoa,
567b877906bSopenharmony_ci        .createWindowSurface = _glfwCreateWindowSurfaceCocoa
568b877906bSopenharmony_ci    };
569b877906bSopenharmony_ci
570b877906bSopenharmony_ci    *platform = cocoa;
571b877906bSopenharmony_ci    return GLFW_TRUE;
572b877906bSopenharmony_ci}
573b877906bSopenharmony_ci
574b877906bSopenharmony_ciint _glfwInitCocoa(void)
575b877906bSopenharmony_ci{
576b877906bSopenharmony_ci    @autoreleasepool {
577b877906bSopenharmony_ci
578b877906bSopenharmony_ci    _glfw.ns.helper = [[GLFWHelper alloc] init];
579b877906bSopenharmony_ci
580b877906bSopenharmony_ci    [NSThread detachNewThreadSelector:@selector(doNothing:)
581b877906bSopenharmony_ci                             toTarget:_glfw.ns.helper
582b877906bSopenharmony_ci                           withObject:nil];
583b877906bSopenharmony_ci
584b877906bSopenharmony_ci    [NSApplication sharedApplication];
585b877906bSopenharmony_ci
586b877906bSopenharmony_ci    _glfw.ns.delegate = [[GLFWApplicationDelegate alloc] init];
587b877906bSopenharmony_ci    if (_glfw.ns.delegate == nil)
588b877906bSopenharmony_ci    {
589b877906bSopenharmony_ci        _glfwInputError(GLFW_PLATFORM_ERROR,
590b877906bSopenharmony_ci                        "Cocoa: Failed to create application delegate");
591b877906bSopenharmony_ci        return GLFW_FALSE;
592b877906bSopenharmony_ci    }
593b877906bSopenharmony_ci
594b877906bSopenharmony_ci    [NSApp setDelegate:_glfw.ns.delegate];
595b877906bSopenharmony_ci
596b877906bSopenharmony_ci    NSEvent* (^block)(NSEvent*) = ^ NSEvent* (NSEvent* event)
597b877906bSopenharmony_ci    {
598b877906bSopenharmony_ci        if ([event modifierFlags] & NSEventModifierFlagCommand)
599b877906bSopenharmony_ci            [[NSApp keyWindow] sendEvent:event];
600b877906bSopenharmony_ci
601b877906bSopenharmony_ci        return event;
602b877906bSopenharmony_ci    };
603b877906bSopenharmony_ci
604b877906bSopenharmony_ci    _glfw.ns.keyUpMonitor =
605b877906bSopenharmony_ci        [NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskKeyUp
606b877906bSopenharmony_ci                                              handler:block];
607b877906bSopenharmony_ci
608b877906bSopenharmony_ci    if (_glfw.hints.init.ns.chdir)
609b877906bSopenharmony_ci        changeToResourcesDirectory();
610b877906bSopenharmony_ci
611b877906bSopenharmony_ci    // Press and Hold prevents some keys from emitting repeated characters
612b877906bSopenharmony_ci    NSDictionary* defaults = @{@"ApplePressAndHoldEnabled":@NO};
613b877906bSopenharmony_ci    [[NSUserDefaults standardUserDefaults] registerDefaults:defaults];
614b877906bSopenharmony_ci
615b877906bSopenharmony_ci    [[NSNotificationCenter defaultCenter]
616b877906bSopenharmony_ci        addObserver:_glfw.ns.helper
617b877906bSopenharmony_ci           selector:@selector(selectedKeyboardInputSourceChanged:)
618b877906bSopenharmony_ci               name:NSTextInputContextKeyboardSelectionDidChangeNotification
619b877906bSopenharmony_ci             object:nil];
620b877906bSopenharmony_ci
621b877906bSopenharmony_ci    createKeyTables();
622b877906bSopenharmony_ci
623b877906bSopenharmony_ci    _glfw.ns.eventSource = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
624b877906bSopenharmony_ci    if (!_glfw.ns.eventSource)
625b877906bSopenharmony_ci        return GLFW_FALSE;
626b877906bSopenharmony_ci
627b877906bSopenharmony_ci    CGEventSourceSetLocalEventsSuppressionInterval(_glfw.ns.eventSource, 0.0);
628b877906bSopenharmony_ci
629b877906bSopenharmony_ci    if (!initializeTIS())
630b877906bSopenharmony_ci        return GLFW_FALSE;
631b877906bSopenharmony_ci
632b877906bSopenharmony_ci    _glfwPollMonitorsCocoa();
633b877906bSopenharmony_ci
634b877906bSopenharmony_ci    if (![[NSRunningApplication currentApplication] isFinishedLaunching])
635b877906bSopenharmony_ci        [NSApp run];
636b877906bSopenharmony_ci
637b877906bSopenharmony_ci    // In case we are unbundled, make us a proper UI application
638b877906bSopenharmony_ci    if (_glfw.hints.init.ns.menubar)
639b877906bSopenharmony_ci        [NSApp setActivationPolicy:NSApplicationActivationPolicyAccessory];
640b877906bSopenharmony_ci
641b877906bSopenharmony_ci    return GLFW_TRUE;
642b877906bSopenharmony_ci
643b877906bSopenharmony_ci    } // autoreleasepool
644b877906bSopenharmony_ci}
645b877906bSopenharmony_ci
646b877906bSopenharmony_civoid _glfwTerminateCocoa(void)
647b877906bSopenharmony_ci{
648b877906bSopenharmony_ci    @autoreleasepool {
649b877906bSopenharmony_ci
650b877906bSopenharmony_ci    if (_glfw.ns.inputSource)
651b877906bSopenharmony_ci    {
652b877906bSopenharmony_ci        CFRelease(_glfw.ns.inputSource);
653b877906bSopenharmony_ci        _glfw.ns.inputSource = NULL;
654b877906bSopenharmony_ci        _glfw.ns.unicodeData = nil;
655b877906bSopenharmony_ci    }
656b877906bSopenharmony_ci
657b877906bSopenharmony_ci    if (_glfw.ns.eventSource)
658b877906bSopenharmony_ci    {
659b877906bSopenharmony_ci        CFRelease(_glfw.ns.eventSource);
660b877906bSopenharmony_ci        _glfw.ns.eventSource = NULL;
661b877906bSopenharmony_ci    }
662b877906bSopenharmony_ci
663b877906bSopenharmony_ci    if (_glfw.ns.delegate)
664b877906bSopenharmony_ci    {
665b877906bSopenharmony_ci        [NSApp setDelegate:nil];
666b877906bSopenharmony_ci        [_glfw.ns.delegate release];
667b877906bSopenharmony_ci        _glfw.ns.delegate = nil;
668b877906bSopenharmony_ci    }
669b877906bSopenharmony_ci
670b877906bSopenharmony_ci    if (_glfw.ns.helper)
671b877906bSopenharmony_ci    {
672b877906bSopenharmony_ci        [[NSNotificationCenter defaultCenter]
673b877906bSopenharmony_ci            removeObserver:_glfw.ns.helper
674b877906bSopenharmony_ci                      name:NSTextInputContextKeyboardSelectionDidChangeNotification
675b877906bSopenharmony_ci                    object:nil];
676b877906bSopenharmony_ci        [[NSNotificationCenter defaultCenter]
677b877906bSopenharmony_ci            removeObserver:_glfw.ns.helper];
678b877906bSopenharmony_ci        [_glfw.ns.helper release];
679b877906bSopenharmony_ci        _glfw.ns.helper = nil;
680b877906bSopenharmony_ci    }
681b877906bSopenharmony_ci
682b877906bSopenharmony_ci    if (_glfw.ns.keyUpMonitor)
683b877906bSopenharmony_ci        [NSEvent removeMonitor:_glfw.ns.keyUpMonitor];
684b877906bSopenharmony_ci
685b877906bSopenharmony_ci    _glfw_free(_glfw.ns.clipboardString);
686b877906bSopenharmony_ci
687b877906bSopenharmony_ci    _glfwTerminateNSGL();
688b877906bSopenharmony_ci    _glfwTerminateEGL();
689b877906bSopenharmony_ci    _glfwTerminateOSMesa();
690b877906bSopenharmony_ci
691b877906bSopenharmony_ci    } // autoreleasepool
692b877906bSopenharmony_ci}
693b877906bSopenharmony_ci
694b877906bSopenharmony_ci#endif // _GLFW_COCOA
695b877906bSopenharmony_ci
696