xref: /aosp_15_r20/external/angle/util/osx/OSXWindow.mm (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1*8975f5c5SAndroid Build Coastguard Worker//
2*8975f5c5SAndroid Build Coastguard Worker// Copyright 2015 The ANGLE Project Authors. All rights reserved.
3*8975f5c5SAndroid Build Coastguard Worker// Use of this source code is governed by a BSD-style license that can be
4*8975f5c5SAndroid Build Coastguard Worker// found in the LICENSE file.
5*8975f5c5SAndroid Build Coastguard Worker//
6*8975f5c5SAndroid Build Coastguard Worker
7*8975f5c5SAndroid Build Coastguard Worker// OSXWindow.mm: Implementation of OSWindow for OSX
8*8975f5c5SAndroid Build Coastguard Worker
9*8975f5c5SAndroid Build Coastguard Worker#include "util/osx/OSXWindow.h"
10*8975f5c5SAndroid Build Coastguard Worker
11*8975f5c5SAndroid Build Coastguard Worker#include <set>
12*8975f5c5SAndroid Build Coastguard Worker// Include Carbon to use the keycode names in Carbon's Event.h
13*8975f5c5SAndroid Build Coastguard Worker#include <Carbon/Carbon.h>
14*8975f5c5SAndroid Build Coastguard Worker
15*8975f5c5SAndroid Build Coastguard Worker#include "anglebase/no_destructor.h"
16*8975f5c5SAndroid Build Coastguard Worker#include "common/debug.h"
17*8975f5c5SAndroid Build Coastguard Worker
18*8975f5c5SAndroid Build Coastguard Worker// On OSX 10.12 a number of AppKit interfaces have been renamed for consistency, and the previous
19*8975f5c5SAndroid Build Coastguard Worker// symbols tagged as deprecated. However we can't simply use the new symbols as it would break
20*8975f5c5SAndroid Build Coastguard Worker// compilation on our automated testing that doesn't use OSX 10.12 yet. So we just ignore the
21*8975f5c5SAndroid Build Coastguard Worker// warnings.
22*8975f5c5SAndroid Build Coastguard Worker#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
23*8975f5c5SAndroid Build Coastguard Worker
24*8975f5c5SAndroid Build Coastguard Worker// Some events such as "ShouldTerminate" are sent to the whole application so we keep a list of
25*8975f5c5SAndroid Build Coastguard Worker// all the windows in order to forward the event to each of them. However this and calling pushEvent
26*8975f5c5SAndroid Build Coastguard Worker// in ApplicationDelegate is inherently unsafe in a multithreaded environment.
27*8975f5c5SAndroid Build Coastguard Workerstatic std::set<OSXWindow *> &AllWindows()
28*8975f5c5SAndroid Build Coastguard Worker{
29*8975f5c5SAndroid Build Coastguard Worker    static angle::base::NoDestructor<std::set<OSXWindow *>> allWindows;
30*8975f5c5SAndroid Build Coastguard Worker    return *allWindows;
31*8975f5c5SAndroid Build Coastguard Worker}
32*8975f5c5SAndroid Build Coastguard Worker
33*8975f5c5SAndroid Build Coastguard Worker@interface Application : NSApplication
34*8975f5c5SAndroid Build Coastguard Worker@end
35*8975f5c5SAndroid Build Coastguard Worker
36*8975f5c5SAndroid Build Coastguard Worker@implementation Application
37*8975f5c5SAndroid Build Coastguard Worker- (void)sendEvent:(NSEvent *)nsEvent
38*8975f5c5SAndroid Build Coastguard Worker{
39*8975f5c5SAndroid Build Coastguard Worker    if ([nsEvent type] == NSApplicationDefined)
40*8975f5c5SAndroid Build Coastguard Worker    {
41*8975f5c5SAndroid Build Coastguard Worker        for (auto window : AllWindows())
42*8975f5c5SAndroid Build Coastguard Worker        {
43*8975f5c5SAndroid Build Coastguard Worker            if ([window->getNSWindow() windowNumber] == [nsEvent windowNumber])
44*8975f5c5SAndroid Build Coastguard Worker            {
45*8975f5c5SAndroid Build Coastguard Worker                Event event;
46*8975f5c5SAndroid Build Coastguard Worker                event.Type = Event::EVENT_TEST;
47*8975f5c5SAndroid Build Coastguard Worker                window->pushEvent(event);
48*8975f5c5SAndroid Build Coastguard Worker            }
49*8975f5c5SAndroid Build Coastguard Worker        }
50*8975f5c5SAndroid Build Coastguard Worker    }
51*8975f5c5SAndroid Build Coastguard Worker    [super sendEvent:nsEvent];
52*8975f5c5SAndroid Build Coastguard Worker}
53*8975f5c5SAndroid Build Coastguard Worker
54*8975f5c5SAndroid Build Coastguard Worker// Override internal method to try to diagnose unexpected crashes in Core Animation.
55*8975f5c5SAndroid Build Coastguard Worker// anglebug.com/42265067
56*8975f5c5SAndroid Build Coastguard Worker// See also:
57*8975f5c5SAndroid Build Coastguard Worker//   https://github.com/microsoft/appcenter-sdk-apple/issues/1944
58*8975f5c5SAndroid Build Coastguard Worker//   https://stackoverflow.com/questions/220159/how-do-you-print-out-a-stack-trace-to-the-console-log-in-cocoa
59*8975f5c5SAndroid Build Coastguard Worker- (void)_crashOnException:(NSException *)exception
60*8975f5c5SAndroid Build Coastguard Worker{
61*8975f5c5SAndroid Build Coastguard Worker    NSLog(@"*** OSXWindow aborting on exception:  <%@> %@", [exception name], [exception reason]);
62*8975f5c5SAndroid Build Coastguard Worker    NSLog(@"%@", [exception callStackSymbols]);
63*8975f5c5SAndroid Build Coastguard Worker    abort();
64*8975f5c5SAndroid Build Coastguard Worker}
65*8975f5c5SAndroid Build Coastguard Worker@end
66*8975f5c5SAndroid Build Coastguard Worker
67*8975f5c5SAndroid Build Coastguard Worker// The Delegate receiving application-wide events.
68*8975f5c5SAndroid Build Coastguard Worker@interface ApplicationDelegate : NSObject
69*8975f5c5SAndroid Build Coastguard Worker@end
70*8975f5c5SAndroid Build Coastguard Worker
71*8975f5c5SAndroid Build Coastguard Worker@implementation ApplicationDelegate
72*8975f5c5SAndroid Build Coastguard Worker- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
73*8975f5c5SAndroid Build Coastguard Worker{
74*8975f5c5SAndroid Build Coastguard Worker    Event event;
75*8975f5c5SAndroid Build Coastguard Worker    event.Type = Event::EVENT_CLOSED;
76*8975f5c5SAndroid Build Coastguard Worker    for (auto window : AllWindows())
77*8975f5c5SAndroid Build Coastguard Worker    {
78*8975f5c5SAndroid Build Coastguard Worker        window->pushEvent(event);
79*8975f5c5SAndroid Build Coastguard Worker    }
80*8975f5c5SAndroid Build Coastguard Worker    return NSTerminateCancel;
81*8975f5c5SAndroid Build Coastguard Worker}
82*8975f5c5SAndroid Build Coastguard Worker@end
83*8975f5c5SAndroid Build Coastguard Workerstatic ApplicationDelegate *gApplicationDelegate = nil;
84*8975f5c5SAndroid Build Coastguard Worker
85*8975f5c5SAndroid Build Coastguard Workerstatic bool InitializeAppKit()
86*8975f5c5SAndroid Build Coastguard Worker{
87*8975f5c5SAndroid Build Coastguard Worker    if (NSApp != nil)
88*8975f5c5SAndroid Build Coastguard Worker    {
89*8975f5c5SAndroid Build Coastguard Worker        return true;
90*8975f5c5SAndroid Build Coastguard Worker    }
91*8975f5c5SAndroid Build Coastguard Worker
92*8975f5c5SAndroid Build Coastguard Worker    // Initialize the global variable "NSApp"
93*8975f5c5SAndroid Build Coastguard Worker    [Application sharedApplication];
94*8975f5c5SAndroid Build Coastguard Worker
95*8975f5c5SAndroid Build Coastguard Worker    // Make us appear in the dock
96*8975f5c5SAndroid Build Coastguard Worker    [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
97*8975f5c5SAndroid Build Coastguard Worker
98*8975f5c5SAndroid Build Coastguard Worker    // Register our global event handler
99*8975f5c5SAndroid Build Coastguard Worker    gApplicationDelegate = [[ApplicationDelegate alloc] init];
100*8975f5c5SAndroid Build Coastguard Worker    if (gApplicationDelegate == nil)
101*8975f5c5SAndroid Build Coastguard Worker    {
102*8975f5c5SAndroid Build Coastguard Worker        return false;
103*8975f5c5SAndroid Build Coastguard Worker    }
104*8975f5c5SAndroid Build Coastguard Worker    [NSApp setDelegate:static_cast<id>(gApplicationDelegate)];
105*8975f5c5SAndroid Build Coastguard Worker
106*8975f5c5SAndroid Build Coastguard Worker    // Set our status to "started" so we are not bouncing in the doc and can activate
107*8975f5c5SAndroid Build Coastguard Worker    [NSApp finishLaunching];
108*8975f5c5SAndroid Build Coastguard Worker    return true;
109*8975f5c5SAndroid Build Coastguard Worker}
110*8975f5c5SAndroid Build Coastguard Worker
111*8975f5c5SAndroid Build Coastguard Worker// NS's and CG's coordinate systems start at the bottom left, while OSWindow's coordinate
112*8975f5c5SAndroid Build Coastguard Worker// system starts at the top left. This function converts the Y coordinate accordingly.
113*8975f5c5SAndroid Build Coastguard Workerstatic float YCoordToFromCG(float y)
114*8975f5c5SAndroid Build Coastguard Worker{
115*8975f5c5SAndroid Build Coastguard Worker    float screenHeight = CGDisplayBounds(CGMainDisplayID()).size.height;
116*8975f5c5SAndroid Build Coastguard Worker    return screenHeight - y;
117*8975f5c5SAndroid Build Coastguard Worker}
118*8975f5c5SAndroid Build Coastguard Worker
119*8975f5c5SAndroid Build Coastguard Worker// Delegate for window-wide events, note that the protocol doesn't contain anything input related.
120*8975f5c5SAndroid Build Coastguard Worker@implementation WindowDelegate
121*8975f5c5SAndroid Build Coastguard Worker- (id)initWithWindow:(OSXWindow *)window
122*8975f5c5SAndroid Build Coastguard Worker{
123*8975f5c5SAndroid Build Coastguard Worker    self = [super init];
124*8975f5c5SAndroid Build Coastguard Worker    if (self != nil)
125*8975f5c5SAndroid Build Coastguard Worker    {
126*8975f5c5SAndroid Build Coastguard Worker        mWindow = window;
127*8975f5c5SAndroid Build Coastguard Worker    }
128*8975f5c5SAndroid Build Coastguard Worker    return self;
129*8975f5c5SAndroid Build Coastguard Worker}
130*8975f5c5SAndroid Build Coastguard Worker
131*8975f5c5SAndroid Build Coastguard Worker- (void)onOSXWindowDeleted
132*8975f5c5SAndroid Build Coastguard Worker{
133*8975f5c5SAndroid Build Coastguard Worker    mWindow = nil;
134*8975f5c5SAndroid Build Coastguard Worker}
135*8975f5c5SAndroid Build Coastguard Worker
136*8975f5c5SAndroid Build Coastguard Worker- (BOOL)windowShouldClose:(id)sender
137*8975f5c5SAndroid Build Coastguard Worker{
138*8975f5c5SAndroid Build Coastguard Worker    Event event;
139*8975f5c5SAndroid Build Coastguard Worker    event.Type = Event::EVENT_CLOSED;
140*8975f5c5SAndroid Build Coastguard Worker    mWindow->pushEvent(event);
141*8975f5c5SAndroid Build Coastguard Worker    return NO;
142*8975f5c5SAndroid Build Coastguard Worker}
143*8975f5c5SAndroid Build Coastguard Worker
144*8975f5c5SAndroid Build Coastguard Worker- (void)windowDidResize:(NSNotification *)notification
145*8975f5c5SAndroid Build Coastguard Worker{
146*8975f5c5SAndroid Build Coastguard Worker    NSSize windowSize = [[mWindow->getNSWindow() contentView] frame].size;
147*8975f5c5SAndroid Build Coastguard Worker    Event event;
148*8975f5c5SAndroid Build Coastguard Worker    event.Type        = Event::EVENT_RESIZED;
149*8975f5c5SAndroid Build Coastguard Worker    event.Size.Width  = (int)windowSize.width;
150*8975f5c5SAndroid Build Coastguard Worker    event.Size.Height = (int)windowSize.height;
151*8975f5c5SAndroid Build Coastguard Worker    mWindow->pushEvent(event);
152*8975f5c5SAndroid Build Coastguard Worker}
153*8975f5c5SAndroid Build Coastguard Worker
154*8975f5c5SAndroid Build Coastguard Worker- (void)windowDidMove:(NSNotification *)notification
155*8975f5c5SAndroid Build Coastguard Worker{
156*8975f5c5SAndroid Build Coastguard Worker    NSRect screenspace = [mWindow->getNSWindow() frame];
157*8975f5c5SAndroid Build Coastguard Worker    Event event;
158*8975f5c5SAndroid Build Coastguard Worker    event.Type   = Event::EVENT_MOVED;
159*8975f5c5SAndroid Build Coastguard Worker    event.Move.X = (int)screenspace.origin.x;
160*8975f5c5SAndroid Build Coastguard Worker    event.Move.Y = (int)YCoordToFromCG(screenspace.origin.y + screenspace.size.height);
161*8975f5c5SAndroid Build Coastguard Worker    mWindow->pushEvent(event);
162*8975f5c5SAndroid Build Coastguard Worker}
163*8975f5c5SAndroid Build Coastguard Worker
164*8975f5c5SAndroid Build Coastguard Worker- (void)windowDidBecomeKey:(NSNotification *)notification
165*8975f5c5SAndroid Build Coastguard Worker{
166*8975f5c5SAndroid Build Coastguard Worker    Event event;
167*8975f5c5SAndroid Build Coastguard Worker    event.Type = Event::EVENT_GAINED_FOCUS;
168*8975f5c5SAndroid Build Coastguard Worker    mWindow->pushEvent(event);
169*8975f5c5SAndroid Build Coastguard Worker    [self retain];
170*8975f5c5SAndroid Build Coastguard Worker}
171*8975f5c5SAndroid Build Coastguard Worker
172*8975f5c5SAndroid Build Coastguard Worker- (void)windowDidResignKey:(NSNotification *)notification
173*8975f5c5SAndroid Build Coastguard Worker{
174*8975f5c5SAndroid Build Coastguard Worker    if (mWindow != nil)
175*8975f5c5SAndroid Build Coastguard Worker    {
176*8975f5c5SAndroid Build Coastguard Worker        Event event;
177*8975f5c5SAndroid Build Coastguard Worker        event.Type = Event::EVENT_LOST_FOCUS;
178*8975f5c5SAndroid Build Coastguard Worker        mWindow->pushEvent(event);
179*8975f5c5SAndroid Build Coastguard Worker    }
180*8975f5c5SAndroid Build Coastguard Worker    [self release];
181*8975f5c5SAndroid Build Coastguard Worker}
182*8975f5c5SAndroid Build Coastguard Worker@end
183*8975f5c5SAndroid Build Coastguard Worker
184*8975f5c5SAndroid Build Coastguard Workerstatic Key NSCodeToKey(int keyCode)
185*8975f5c5SAndroid Build Coastguard Worker{
186*8975f5c5SAndroid Build Coastguard Worker    // Missing KEY_PAUSE
187*8975f5c5SAndroid Build Coastguard Worker    switch (keyCode)
188*8975f5c5SAndroid Build Coastguard Worker    {
189*8975f5c5SAndroid Build Coastguard Worker        case kVK_Shift:
190*8975f5c5SAndroid Build Coastguard Worker            return KEY_LSHIFT;
191*8975f5c5SAndroid Build Coastguard Worker        case kVK_RightShift:
192*8975f5c5SAndroid Build Coastguard Worker            return KEY_RSHIFT;
193*8975f5c5SAndroid Build Coastguard Worker        case kVK_Option:
194*8975f5c5SAndroid Build Coastguard Worker            return KEY_LALT;
195*8975f5c5SAndroid Build Coastguard Worker        case kVK_RightOption:
196*8975f5c5SAndroid Build Coastguard Worker            return KEY_RALT;
197*8975f5c5SAndroid Build Coastguard Worker        case kVK_Control:
198*8975f5c5SAndroid Build Coastguard Worker            return KEY_LCONTROL;
199*8975f5c5SAndroid Build Coastguard Worker        case kVK_RightControl:
200*8975f5c5SAndroid Build Coastguard Worker            return KEY_RCONTROL;
201*8975f5c5SAndroid Build Coastguard Worker        case kVK_Command:
202*8975f5c5SAndroid Build Coastguard Worker            return KEY_LSYSTEM;
203*8975f5c5SAndroid Build Coastguard Worker        // Right System doesn't have a name, but shows up as 0x36.
204*8975f5c5SAndroid Build Coastguard Worker        case 0x36:
205*8975f5c5SAndroid Build Coastguard Worker            return KEY_RSYSTEM;
206*8975f5c5SAndroid Build Coastguard Worker        case kVK_Function:
207*8975f5c5SAndroid Build Coastguard Worker            return KEY_MENU;
208*8975f5c5SAndroid Build Coastguard Worker
209*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_Semicolon:
210*8975f5c5SAndroid Build Coastguard Worker            return KEY_SEMICOLON;
211*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_Slash:
212*8975f5c5SAndroid Build Coastguard Worker            return KEY_SLASH;
213*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_Equal:
214*8975f5c5SAndroid Build Coastguard Worker            return KEY_EQUAL;
215*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_Minus:
216*8975f5c5SAndroid Build Coastguard Worker            return KEY_DASH;
217*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_LeftBracket:
218*8975f5c5SAndroid Build Coastguard Worker            return KEY_LBRACKET;
219*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_RightBracket:
220*8975f5c5SAndroid Build Coastguard Worker            return KEY_RBRACKET;
221*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_Comma:
222*8975f5c5SAndroid Build Coastguard Worker            return KEY_COMMA;
223*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_Period:
224*8975f5c5SAndroid Build Coastguard Worker            return KEY_PERIOD;
225*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_Backslash:
226*8975f5c5SAndroid Build Coastguard Worker            return KEY_BACKSLASH;
227*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_Grave:
228*8975f5c5SAndroid Build Coastguard Worker            return KEY_TILDE;
229*8975f5c5SAndroid Build Coastguard Worker        case kVK_Escape:
230*8975f5c5SAndroid Build Coastguard Worker            return KEY_ESCAPE;
231*8975f5c5SAndroid Build Coastguard Worker        case kVK_Space:
232*8975f5c5SAndroid Build Coastguard Worker            return KEY_SPACE;
233*8975f5c5SAndroid Build Coastguard Worker        case kVK_Return:
234*8975f5c5SAndroid Build Coastguard Worker            return KEY_RETURN;
235*8975f5c5SAndroid Build Coastguard Worker        case kVK_Delete:
236*8975f5c5SAndroid Build Coastguard Worker            return KEY_BACK;
237*8975f5c5SAndroid Build Coastguard Worker        case kVK_Tab:
238*8975f5c5SAndroid Build Coastguard Worker            return KEY_TAB;
239*8975f5c5SAndroid Build Coastguard Worker        case kVK_PageUp:
240*8975f5c5SAndroid Build Coastguard Worker            return KEY_PAGEUP;
241*8975f5c5SAndroid Build Coastguard Worker        case kVK_PageDown:
242*8975f5c5SAndroid Build Coastguard Worker            return KEY_PAGEDOWN;
243*8975f5c5SAndroid Build Coastguard Worker        case kVK_End:
244*8975f5c5SAndroid Build Coastguard Worker            return KEY_END;
245*8975f5c5SAndroid Build Coastguard Worker        case kVK_Home:
246*8975f5c5SAndroid Build Coastguard Worker            return KEY_HOME;
247*8975f5c5SAndroid Build Coastguard Worker        case kVK_Help:
248*8975f5c5SAndroid Build Coastguard Worker            return KEY_INSERT;
249*8975f5c5SAndroid Build Coastguard Worker        case kVK_ForwardDelete:
250*8975f5c5SAndroid Build Coastguard Worker            return KEY_DELETE;
251*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_KeypadPlus:
252*8975f5c5SAndroid Build Coastguard Worker            return KEY_ADD;
253*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_KeypadMinus:
254*8975f5c5SAndroid Build Coastguard Worker            return KEY_SUBTRACT;
255*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_KeypadMultiply:
256*8975f5c5SAndroid Build Coastguard Worker            return KEY_MULTIPLY;
257*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_KeypadDivide:
258*8975f5c5SAndroid Build Coastguard Worker            return KEY_DIVIDE;
259*8975f5c5SAndroid Build Coastguard Worker
260*8975f5c5SAndroid Build Coastguard Worker        case kVK_F1:
261*8975f5c5SAndroid Build Coastguard Worker            return KEY_F1;
262*8975f5c5SAndroid Build Coastguard Worker        case kVK_F2:
263*8975f5c5SAndroid Build Coastguard Worker            return KEY_F2;
264*8975f5c5SAndroid Build Coastguard Worker        case kVK_F3:
265*8975f5c5SAndroid Build Coastguard Worker            return KEY_F3;
266*8975f5c5SAndroid Build Coastguard Worker        case kVK_F4:
267*8975f5c5SAndroid Build Coastguard Worker            return KEY_F4;
268*8975f5c5SAndroid Build Coastguard Worker        case kVK_F5:
269*8975f5c5SAndroid Build Coastguard Worker            return KEY_F5;
270*8975f5c5SAndroid Build Coastguard Worker        case kVK_F6:
271*8975f5c5SAndroid Build Coastguard Worker            return KEY_F6;
272*8975f5c5SAndroid Build Coastguard Worker        case kVK_F7:
273*8975f5c5SAndroid Build Coastguard Worker            return KEY_F7;
274*8975f5c5SAndroid Build Coastguard Worker        case kVK_F8:
275*8975f5c5SAndroid Build Coastguard Worker            return KEY_F8;
276*8975f5c5SAndroid Build Coastguard Worker        case kVK_F9:
277*8975f5c5SAndroid Build Coastguard Worker            return KEY_F9;
278*8975f5c5SAndroid Build Coastguard Worker        case kVK_F10:
279*8975f5c5SAndroid Build Coastguard Worker            return KEY_F10;
280*8975f5c5SAndroid Build Coastguard Worker        case kVK_F11:
281*8975f5c5SAndroid Build Coastguard Worker            return KEY_F11;
282*8975f5c5SAndroid Build Coastguard Worker        case kVK_F12:
283*8975f5c5SAndroid Build Coastguard Worker            return KEY_F12;
284*8975f5c5SAndroid Build Coastguard Worker        case kVK_F13:
285*8975f5c5SAndroid Build Coastguard Worker            return KEY_F13;
286*8975f5c5SAndroid Build Coastguard Worker        case kVK_F14:
287*8975f5c5SAndroid Build Coastguard Worker            return KEY_F14;
288*8975f5c5SAndroid Build Coastguard Worker        case kVK_F15:
289*8975f5c5SAndroid Build Coastguard Worker            return KEY_F15;
290*8975f5c5SAndroid Build Coastguard Worker
291*8975f5c5SAndroid Build Coastguard Worker        case kVK_LeftArrow:
292*8975f5c5SAndroid Build Coastguard Worker            return KEY_LEFT;
293*8975f5c5SAndroid Build Coastguard Worker        case kVK_RightArrow:
294*8975f5c5SAndroid Build Coastguard Worker            return KEY_RIGHT;
295*8975f5c5SAndroid Build Coastguard Worker        case kVK_DownArrow:
296*8975f5c5SAndroid Build Coastguard Worker            return KEY_DOWN;
297*8975f5c5SAndroid Build Coastguard Worker        case kVK_UpArrow:
298*8975f5c5SAndroid Build Coastguard Worker            return KEY_UP;
299*8975f5c5SAndroid Build Coastguard Worker
300*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_Keypad0:
301*8975f5c5SAndroid Build Coastguard Worker            return KEY_NUMPAD0;
302*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_Keypad1:
303*8975f5c5SAndroid Build Coastguard Worker            return KEY_NUMPAD1;
304*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_Keypad2:
305*8975f5c5SAndroid Build Coastguard Worker            return KEY_NUMPAD2;
306*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_Keypad3:
307*8975f5c5SAndroid Build Coastguard Worker            return KEY_NUMPAD3;
308*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_Keypad4:
309*8975f5c5SAndroid Build Coastguard Worker            return KEY_NUMPAD4;
310*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_Keypad5:
311*8975f5c5SAndroid Build Coastguard Worker            return KEY_NUMPAD5;
312*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_Keypad6:
313*8975f5c5SAndroid Build Coastguard Worker            return KEY_NUMPAD6;
314*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_Keypad7:
315*8975f5c5SAndroid Build Coastguard Worker            return KEY_NUMPAD7;
316*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_Keypad8:
317*8975f5c5SAndroid Build Coastguard Worker            return KEY_NUMPAD8;
318*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_Keypad9:
319*8975f5c5SAndroid Build Coastguard Worker            return KEY_NUMPAD9;
320*8975f5c5SAndroid Build Coastguard Worker
321*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_A:
322*8975f5c5SAndroid Build Coastguard Worker            return KEY_A;
323*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_B:
324*8975f5c5SAndroid Build Coastguard Worker            return KEY_B;
325*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_C:
326*8975f5c5SAndroid Build Coastguard Worker            return KEY_C;
327*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_D:
328*8975f5c5SAndroid Build Coastguard Worker            return KEY_D;
329*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_E:
330*8975f5c5SAndroid Build Coastguard Worker            return KEY_E;
331*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_F:
332*8975f5c5SAndroid Build Coastguard Worker            return KEY_F;
333*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_G:
334*8975f5c5SAndroid Build Coastguard Worker            return KEY_G;
335*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_H:
336*8975f5c5SAndroid Build Coastguard Worker            return KEY_H;
337*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_I:
338*8975f5c5SAndroid Build Coastguard Worker            return KEY_I;
339*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_J:
340*8975f5c5SAndroid Build Coastguard Worker            return KEY_J;
341*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_K:
342*8975f5c5SAndroid Build Coastguard Worker            return KEY_K;
343*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_L:
344*8975f5c5SAndroid Build Coastguard Worker            return KEY_L;
345*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_M:
346*8975f5c5SAndroid Build Coastguard Worker            return KEY_M;
347*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_N:
348*8975f5c5SAndroid Build Coastguard Worker            return KEY_N;
349*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_O:
350*8975f5c5SAndroid Build Coastguard Worker            return KEY_O;
351*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_P:
352*8975f5c5SAndroid Build Coastguard Worker            return KEY_P;
353*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_Q:
354*8975f5c5SAndroid Build Coastguard Worker            return KEY_Q;
355*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_R:
356*8975f5c5SAndroid Build Coastguard Worker            return KEY_R;
357*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_S:
358*8975f5c5SAndroid Build Coastguard Worker            return KEY_S;
359*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_T:
360*8975f5c5SAndroid Build Coastguard Worker            return KEY_T;
361*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_U:
362*8975f5c5SAndroid Build Coastguard Worker            return KEY_U;
363*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_V:
364*8975f5c5SAndroid Build Coastguard Worker            return KEY_V;
365*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_W:
366*8975f5c5SAndroid Build Coastguard Worker            return KEY_W;
367*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_X:
368*8975f5c5SAndroid Build Coastguard Worker            return KEY_X;
369*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_Y:
370*8975f5c5SAndroid Build Coastguard Worker            return KEY_Y;
371*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_Z:
372*8975f5c5SAndroid Build Coastguard Worker            return KEY_Z;
373*8975f5c5SAndroid Build Coastguard Worker
374*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_1:
375*8975f5c5SAndroid Build Coastguard Worker            return KEY_NUM1;
376*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_2:
377*8975f5c5SAndroid Build Coastguard Worker            return KEY_NUM2;
378*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_3:
379*8975f5c5SAndroid Build Coastguard Worker            return KEY_NUM3;
380*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_4:
381*8975f5c5SAndroid Build Coastguard Worker            return KEY_NUM4;
382*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_5:
383*8975f5c5SAndroid Build Coastguard Worker            return KEY_NUM5;
384*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_6:
385*8975f5c5SAndroid Build Coastguard Worker            return KEY_NUM6;
386*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_7:
387*8975f5c5SAndroid Build Coastguard Worker            return KEY_NUM7;
388*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_8:
389*8975f5c5SAndroid Build Coastguard Worker            return KEY_NUM8;
390*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_9:
391*8975f5c5SAndroid Build Coastguard Worker            return KEY_NUM9;
392*8975f5c5SAndroid Build Coastguard Worker        case kVK_ANSI_0:
393*8975f5c5SAndroid Build Coastguard Worker            return KEY_NUM0;
394*8975f5c5SAndroid Build Coastguard Worker    }
395*8975f5c5SAndroid Build Coastguard Worker
396*8975f5c5SAndroid Build Coastguard Worker    return Key(0);
397*8975f5c5SAndroid Build Coastguard Worker}
398*8975f5c5SAndroid Build Coastguard Worker
399*8975f5c5SAndroid Build Coastguard Workerstatic void AddNSKeyStateToEvent(Event *event, NSEventModifierFlags state)
400*8975f5c5SAndroid Build Coastguard Worker{
401*8975f5c5SAndroid Build Coastguard Worker    event->Key.Shift   = state & NSShiftKeyMask;
402*8975f5c5SAndroid Build Coastguard Worker    event->Key.Control = state & NSControlKeyMask;
403*8975f5c5SAndroid Build Coastguard Worker    event->Key.Alt     = state & NSAlternateKeyMask;
404*8975f5c5SAndroid Build Coastguard Worker    event->Key.System  = state & NSCommandKeyMask;
405*8975f5c5SAndroid Build Coastguard Worker}
406*8975f5c5SAndroid Build Coastguard Worker
407*8975f5c5SAndroid Build Coastguard Workerstatic MouseButton TranslateMouseButton(NSInteger button)
408*8975f5c5SAndroid Build Coastguard Worker{
409*8975f5c5SAndroid Build Coastguard Worker    switch (button)
410*8975f5c5SAndroid Build Coastguard Worker    {
411*8975f5c5SAndroid Build Coastguard Worker        case 2:
412*8975f5c5SAndroid Build Coastguard Worker            return MOUSEBUTTON_MIDDLE;
413*8975f5c5SAndroid Build Coastguard Worker        case 3:
414*8975f5c5SAndroid Build Coastguard Worker            return MOUSEBUTTON_BUTTON4;
415*8975f5c5SAndroid Build Coastguard Worker        case 4:
416*8975f5c5SAndroid Build Coastguard Worker            return MOUSEBUTTON_BUTTON5;
417*8975f5c5SAndroid Build Coastguard Worker        default:
418*8975f5c5SAndroid Build Coastguard Worker            return MOUSEBUTTON_UNKNOWN;
419*8975f5c5SAndroid Build Coastguard Worker    }
420*8975f5c5SAndroid Build Coastguard Worker}
421*8975f5c5SAndroid Build Coastguard Worker
422*8975f5c5SAndroid Build Coastguard Worker// Delegate for NSView events, mostly the input events
423*8975f5c5SAndroid Build Coastguard Worker@implementation ContentView
424*8975f5c5SAndroid Build Coastguard Worker- (id)initWithWindow:(OSXWindow *)window
425*8975f5c5SAndroid Build Coastguard Worker{
426*8975f5c5SAndroid Build Coastguard Worker    self = [super init];
427*8975f5c5SAndroid Build Coastguard Worker    if (self != nil)
428*8975f5c5SAndroid Build Coastguard Worker    {
429*8975f5c5SAndroid Build Coastguard Worker        mWindow          = window;
430*8975f5c5SAndroid Build Coastguard Worker        mTrackingArea    = nil;
431*8975f5c5SAndroid Build Coastguard Worker        mCurrentModifier = 0;
432*8975f5c5SAndroid Build Coastguard Worker        [self updateTrackingAreas];
433*8975f5c5SAndroid Build Coastguard Worker    }
434*8975f5c5SAndroid Build Coastguard Worker    return self;
435*8975f5c5SAndroid Build Coastguard Worker}
436*8975f5c5SAndroid Build Coastguard Worker
437*8975f5c5SAndroid Build Coastguard Worker- (void)dealloc
438*8975f5c5SAndroid Build Coastguard Worker{
439*8975f5c5SAndroid Build Coastguard Worker    [mTrackingArea release];
440*8975f5c5SAndroid Build Coastguard Worker    [super dealloc];
441*8975f5c5SAndroid Build Coastguard Worker}
442*8975f5c5SAndroid Build Coastguard Worker
443*8975f5c5SAndroid Build Coastguard Worker- (void)updateTrackingAreas
444*8975f5c5SAndroid Build Coastguard Worker{
445*8975f5c5SAndroid Build Coastguard Worker    if (mTrackingArea != nil)
446*8975f5c5SAndroid Build Coastguard Worker    {
447*8975f5c5SAndroid Build Coastguard Worker        [self removeTrackingArea:mTrackingArea];
448*8975f5c5SAndroid Build Coastguard Worker        [mTrackingArea release];
449*8975f5c5SAndroid Build Coastguard Worker        mTrackingArea = nil;
450*8975f5c5SAndroid Build Coastguard Worker    }
451*8975f5c5SAndroid Build Coastguard Worker
452*8975f5c5SAndroid Build Coastguard Worker    NSRect bounds               = [self bounds];
453*8975f5c5SAndroid Build Coastguard Worker    NSTrackingAreaOptions flags = NSTrackingMouseEnteredAndExited | NSTrackingActiveInKeyWindow |
454*8975f5c5SAndroid Build Coastguard Worker                                  NSTrackingCursorUpdate | NSTrackingInVisibleRect |
455*8975f5c5SAndroid Build Coastguard Worker                                  NSTrackingAssumeInside;
456*8975f5c5SAndroid Build Coastguard Worker    mTrackingArea = [[NSTrackingArea alloc] initWithRect:bounds
457*8975f5c5SAndroid Build Coastguard Worker                                                 options:flags
458*8975f5c5SAndroid Build Coastguard Worker                                                   owner:self
459*8975f5c5SAndroid Build Coastguard Worker                                                userInfo:nil];
460*8975f5c5SAndroid Build Coastguard Worker
461*8975f5c5SAndroid Build Coastguard Worker    [self addTrackingArea:mTrackingArea];
462*8975f5c5SAndroid Build Coastguard Worker    [super updateTrackingAreas];
463*8975f5c5SAndroid Build Coastguard Worker}
464*8975f5c5SAndroid Build Coastguard Worker
465*8975f5c5SAndroid Build Coastguard Worker// Helps with performance
466*8975f5c5SAndroid Build Coastguard Worker- (BOOL)isOpaque
467*8975f5c5SAndroid Build Coastguard Worker{
468*8975f5c5SAndroid Build Coastguard Worker    return YES;
469*8975f5c5SAndroid Build Coastguard Worker}
470*8975f5c5SAndroid Build Coastguard Worker
471*8975f5c5SAndroid Build Coastguard Worker- (BOOL)canBecomeKeyView
472*8975f5c5SAndroid Build Coastguard Worker{
473*8975f5c5SAndroid Build Coastguard Worker    return YES;
474*8975f5c5SAndroid Build Coastguard Worker}
475*8975f5c5SAndroid Build Coastguard Worker
476*8975f5c5SAndroid Build Coastguard Worker- (BOOL)acceptsFirstResponder
477*8975f5c5SAndroid Build Coastguard Worker{
478*8975f5c5SAndroid Build Coastguard Worker    return YES;
479*8975f5c5SAndroid Build Coastguard Worker}
480*8975f5c5SAndroid Build Coastguard Worker
481*8975f5c5SAndroid Build Coastguard Worker// Handle mouse events from the NSResponder protocol
482*8975f5c5SAndroid Build Coastguard Worker- (float)translateMouseY:(float)y
483*8975f5c5SAndroid Build Coastguard Worker{
484*8975f5c5SAndroid Build Coastguard Worker    return [self frame].size.height - y;
485*8975f5c5SAndroid Build Coastguard Worker}
486*8975f5c5SAndroid Build Coastguard Worker
487*8975f5c5SAndroid Build Coastguard Worker- (void)addButtonEvent:(NSEvent *)nsEvent
488*8975f5c5SAndroid Build Coastguard Worker                  type:(Event::EventType)eventType
489*8975f5c5SAndroid Build Coastguard Worker                button:(MouseButton)button
490*8975f5c5SAndroid Build Coastguard Worker{
491*8975f5c5SAndroid Build Coastguard Worker    Event event;
492*8975f5c5SAndroid Build Coastguard Worker    event.Type               = eventType;
493*8975f5c5SAndroid Build Coastguard Worker    event.MouseButton.Button = button;
494*8975f5c5SAndroid Build Coastguard Worker    event.MouseButton.X      = (int)[nsEvent locationInWindow].x;
495*8975f5c5SAndroid Build Coastguard Worker    event.MouseButton.Y      = (int)[self translateMouseY:[nsEvent locationInWindow].y];
496*8975f5c5SAndroid Build Coastguard Worker    mWindow->pushEvent(event);
497*8975f5c5SAndroid Build Coastguard Worker}
498*8975f5c5SAndroid Build Coastguard Worker
499*8975f5c5SAndroid Build Coastguard Worker- (void)mouseDown:(NSEvent *)event
500*8975f5c5SAndroid Build Coastguard Worker{
501*8975f5c5SAndroid Build Coastguard Worker    [self addButtonEvent:event type:Event::EVENT_MOUSE_BUTTON_PRESSED button:MOUSEBUTTON_LEFT];
502*8975f5c5SAndroid Build Coastguard Worker}
503*8975f5c5SAndroid Build Coastguard Worker
504*8975f5c5SAndroid Build Coastguard Worker- (void)mouseDragged:(NSEvent *)event
505*8975f5c5SAndroid Build Coastguard Worker{
506*8975f5c5SAndroid Build Coastguard Worker    [self mouseMoved:event];
507*8975f5c5SAndroid Build Coastguard Worker}
508*8975f5c5SAndroid Build Coastguard Worker
509*8975f5c5SAndroid Build Coastguard Worker- (void)mouseUp:(NSEvent *)event
510*8975f5c5SAndroid Build Coastguard Worker{
511*8975f5c5SAndroid Build Coastguard Worker    [self addButtonEvent:event type:Event::EVENT_MOUSE_BUTTON_RELEASED button:MOUSEBUTTON_LEFT];
512*8975f5c5SAndroid Build Coastguard Worker}
513*8975f5c5SAndroid Build Coastguard Worker
514*8975f5c5SAndroid Build Coastguard Worker- (void)mouseMoved:(NSEvent *)nsEvent
515*8975f5c5SAndroid Build Coastguard Worker{
516*8975f5c5SAndroid Build Coastguard Worker    Event event;
517*8975f5c5SAndroid Build Coastguard Worker    event.Type        = Event::EVENT_MOUSE_MOVED;
518*8975f5c5SAndroid Build Coastguard Worker    event.MouseMove.X = (int)[nsEvent locationInWindow].x;
519*8975f5c5SAndroid Build Coastguard Worker    event.MouseMove.Y = (int)[self translateMouseY:[nsEvent locationInWindow].y];
520*8975f5c5SAndroid Build Coastguard Worker    mWindow->pushEvent(event);
521*8975f5c5SAndroid Build Coastguard Worker}
522*8975f5c5SAndroid Build Coastguard Worker
523*8975f5c5SAndroid Build Coastguard Worker- (void)mouseEntered:(NSEvent *)nsEvent
524*8975f5c5SAndroid Build Coastguard Worker{
525*8975f5c5SAndroid Build Coastguard Worker    Event event;
526*8975f5c5SAndroid Build Coastguard Worker    event.Type = Event::EVENT_MOUSE_ENTERED;
527*8975f5c5SAndroid Build Coastguard Worker    mWindow->pushEvent(event);
528*8975f5c5SAndroid Build Coastguard Worker}
529*8975f5c5SAndroid Build Coastguard Worker
530*8975f5c5SAndroid Build Coastguard Worker- (void)mouseExited:(NSEvent *)nsEvent
531*8975f5c5SAndroid Build Coastguard Worker{
532*8975f5c5SAndroid Build Coastguard Worker    Event event;
533*8975f5c5SAndroid Build Coastguard Worker    event.Type = Event::EVENT_MOUSE_LEFT;
534*8975f5c5SAndroid Build Coastguard Worker    mWindow->pushEvent(event);
535*8975f5c5SAndroid Build Coastguard Worker}
536*8975f5c5SAndroid Build Coastguard Worker
537*8975f5c5SAndroid Build Coastguard Worker- (void)rightMouseDown:(NSEvent *)event
538*8975f5c5SAndroid Build Coastguard Worker{
539*8975f5c5SAndroid Build Coastguard Worker    [self addButtonEvent:event type:Event::EVENT_MOUSE_BUTTON_PRESSED button:MOUSEBUTTON_RIGHT];
540*8975f5c5SAndroid Build Coastguard Worker}
541*8975f5c5SAndroid Build Coastguard Worker
542*8975f5c5SAndroid Build Coastguard Worker- (void)rightMouseDragged:(NSEvent *)event
543*8975f5c5SAndroid Build Coastguard Worker{
544*8975f5c5SAndroid Build Coastguard Worker    [self mouseMoved:event];
545*8975f5c5SAndroid Build Coastguard Worker}
546*8975f5c5SAndroid Build Coastguard Worker
547*8975f5c5SAndroid Build Coastguard Worker- (void)rightMouseUp:(NSEvent *)event
548*8975f5c5SAndroid Build Coastguard Worker{
549*8975f5c5SAndroid Build Coastguard Worker    [self addButtonEvent:event type:Event::EVENT_MOUSE_BUTTON_RELEASED button:MOUSEBUTTON_RIGHT];
550*8975f5c5SAndroid Build Coastguard Worker}
551*8975f5c5SAndroid Build Coastguard Worker
552*8975f5c5SAndroid Build Coastguard Worker- (void)otherMouseDown:(NSEvent *)event
553*8975f5c5SAndroid Build Coastguard Worker{
554*8975f5c5SAndroid Build Coastguard Worker    [self addButtonEvent:event
555*8975f5c5SAndroid Build Coastguard Worker                    type:Event::EVENT_MOUSE_BUTTON_PRESSED
556*8975f5c5SAndroid Build Coastguard Worker                  button:TranslateMouseButton([event buttonNumber])];
557*8975f5c5SAndroid Build Coastguard Worker}
558*8975f5c5SAndroid Build Coastguard Worker
559*8975f5c5SAndroid Build Coastguard Worker- (void)otherMouseDragged:(NSEvent *)event
560*8975f5c5SAndroid Build Coastguard Worker{
561*8975f5c5SAndroid Build Coastguard Worker    [self mouseMoved:event];
562*8975f5c5SAndroid Build Coastguard Worker}
563*8975f5c5SAndroid Build Coastguard Worker
564*8975f5c5SAndroid Build Coastguard Worker- (void)otherMouseUp:(NSEvent *)event
565*8975f5c5SAndroid Build Coastguard Worker{
566*8975f5c5SAndroid Build Coastguard Worker    [self addButtonEvent:event
567*8975f5c5SAndroid Build Coastguard Worker                    type:Event::EVENT_MOUSE_BUTTON_RELEASED
568*8975f5c5SAndroid Build Coastguard Worker                  button:TranslateMouseButton([event buttonNumber])];
569*8975f5c5SAndroid Build Coastguard Worker}
570*8975f5c5SAndroid Build Coastguard Worker
571*8975f5c5SAndroid Build Coastguard Worker- (void)scrollWheel:(NSEvent *)nsEvent
572*8975f5c5SAndroid Build Coastguard Worker{
573*8975f5c5SAndroid Build Coastguard Worker    if (static_cast<int>([nsEvent deltaY]) == 0)
574*8975f5c5SAndroid Build Coastguard Worker    {
575*8975f5c5SAndroid Build Coastguard Worker        return;
576*8975f5c5SAndroid Build Coastguard Worker    }
577*8975f5c5SAndroid Build Coastguard Worker
578*8975f5c5SAndroid Build Coastguard Worker    Event event;
579*8975f5c5SAndroid Build Coastguard Worker    event.Type             = Event::EVENT_MOUSE_WHEEL_MOVED;
580*8975f5c5SAndroid Build Coastguard Worker    event.MouseWheel.Delta = (int)[nsEvent deltaY];
581*8975f5c5SAndroid Build Coastguard Worker    mWindow->pushEvent(event);
582*8975f5c5SAndroid Build Coastguard Worker}
583*8975f5c5SAndroid Build Coastguard Worker
584*8975f5c5SAndroid Build Coastguard Worker// Handle key events from the NSResponder protocol
585*8975f5c5SAndroid Build Coastguard Worker- (void)keyDown:(NSEvent *)nsEvent
586*8975f5c5SAndroid Build Coastguard Worker{
587*8975f5c5SAndroid Build Coastguard Worker    // TODO(cwallez) also send text events
588*8975f5c5SAndroid Build Coastguard Worker    Event event;
589*8975f5c5SAndroid Build Coastguard Worker    event.Type     = Event::EVENT_KEY_PRESSED;
590*8975f5c5SAndroid Build Coastguard Worker    event.Key.Code = NSCodeToKey([nsEvent keyCode]);
591*8975f5c5SAndroid Build Coastguard Worker    AddNSKeyStateToEvent(&event, [nsEvent modifierFlags]);
592*8975f5c5SAndroid Build Coastguard Worker    mWindow->pushEvent(event);
593*8975f5c5SAndroid Build Coastguard Worker}
594*8975f5c5SAndroid Build Coastguard Worker
595*8975f5c5SAndroid Build Coastguard Worker- (void)keyUp:(NSEvent *)nsEvent
596*8975f5c5SAndroid Build Coastguard Worker{
597*8975f5c5SAndroid Build Coastguard Worker    Event event;
598*8975f5c5SAndroid Build Coastguard Worker    event.Type     = Event::EVENT_KEY_RELEASED;
599*8975f5c5SAndroid Build Coastguard Worker    event.Key.Code = NSCodeToKey([nsEvent keyCode]);
600*8975f5c5SAndroid Build Coastguard Worker    AddNSKeyStateToEvent(&event, [nsEvent modifierFlags]);
601*8975f5c5SAndroid Build Coastguard Worker    mWindow->pushEvent(event);
602*8975f5c5SAndroid Build Coastguard Worker}
603*8975f5c5SAndroid Build Coastguard Worker
604*8975f5c5SAndroid Build Coastguard Worker// Modifier keys do not trigger keyUp/Down events but only flagsChanged events.
605*8975f5c5SAndroid Build Coastguard Worker- (void)flagsChanged:(NSEvent *)nsEvent
606*8975f5c5SAndroid Build Coastguard Worker{
607*8975f5c5SAndroid Build Coastguard Worker    Event event;
608*8975f5c5SAndroid Build Coastguard Worker
609*8975f5c5SAndroid Build Coastguard Worker    // Guess if the key has been pressed or released with the change of modifiers
610*8975f5c5SAndroid Build Coastguard Worker    // It currently doesn't work when modifiers are unchanged, such as when pressing
611*8975f5c5SAndroid Build Coastguard Worker    // both shift keys. GLFW has a solution for this but it requires tracking the
612*8975f5c5SAndroid Build Coastguard Worker    // state of the keys. Implementing this is still TODO(cwallez)
613*8975f5c5SAndroid Build Coastguard Worker    int modifier = [nsEvent modifierFlags] & NSDeviceIndependentModifierFlagsMask;
614*8975f5c5SAndroid Build Coastguard Worker    if (modifier < mCurrentModifier)
615*8975f5c5SAndroid Build Coastguard Worker    {
616*8975f5c5SAndroid Build Coastguard Worker        event.Type = Event::EVENT_KEY_RELEASED;
617*8975f5c5SAndroid Build Coastguard Worker    }
618*8975f5c5SAndroid Build Coastguard Worker    else
619*8975f5c5SAndroid Build Coastguard Worker    {
620*8975f5c5SAndroid Build Coastguard Worker        event.Type = Event::EVENT_KEY_PRESSED;
621*8975f5c5SAndroid Build Coastguard Worker    }
622*8975f5c5SAndroid Build Coastguard Worker    mCurrentModifier = modifier;
623*8975f5c5SAndroid Build Coastguard Worker
624*8975f5c5SAndroid Build Coastguard Worker    event.Key.Code = NSCodeToKey([nsEvent keyCode]);
625*8975f5c5SAndroid Build Coastguard Worker    AddNSKeyStateToEvent(&event, [nsEvent modifierFlags]);
626*8975f5c5SAndroid Build Coastguard Worker    mWindow->pushEvent(event);
627*8975f5c5SAndroid Build Coastguard Worker}
628*8975f5c5SAndroid Build Coastguard Worker@end
629*8975f5c5SAndroid Build Coastguard Worker
630*8975f5c5SAndroid Build Coastguard WorkerOSXWindow::OSXWindow() : mWindow(nil), mDelegate(nil), mView(nil) {}
631*8975f5c5SAndroid Build Coastguard Worker
632*8975f5c5SAndroid Build Coastguard WorkerOSXWindow::~OSXWindow()
633*8975f5c5SAndroid Build Coastguard Worker{
634*8975f5c5SAndroid Build Coastguard Worker    destroy();
635*8975f5c5SAndroid Build Coastguard Worker}
636*8975f5c5SAndroid Build Coastguard Worker
637*8975f5c5SAndroid Build Coastguard Workerbool OSXWindow::initializeImpl(const std::string &name, int width, int height)
638*8975f5c5SAndroid Build Coastguard Worker{
639*8975f5c5SAndroid Build Coastguard Worker    if (!InitializeAppKit())
640*8975f5c5SAndroid Build Coastguard Worker    {
641*8975f5c5SAndroid Build Coastguard Worker        return false;
642*8975f5c5SAndroid Build Coastguard Worker    }
643*8975f5c5SAndroid Build Coastguard Worker
644*8975f5c5SAndroid Build Coastguard Worker    unsigned int styleMask = NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask |
645*8975f5c5SAndroid Build Coastguard Worker                             NSMiniaturizableWindowMask;
646*8975f5c5SAndroid Build Coastguard Worker    mWindow = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, width, height)
647*8975f5c5SAndroid Build Coastguard Worker                                          styleMask:styleMask
648*8975f5c5SAndroid Build Coastguard Worker                                            backing:NSBackingStoreBuffered
649*8975f5c5SAndroid Build Coastguard Worker                                              defer:NO];
650*8975f5c5SAndroid Build Coastguard Worker
651*8975f5c5SAndroid Build Coastguard Worker    if (mWindow == nil)
652*8975f5c5SAndroid Build Coastguard Worker    {
653*8975f5c5SAndroid Build Coastguard Worker        return false;
654*8975f5c5SAndroid Build Coastguard Worker    }
655*8975f5c5SAndroid Build Coastguard Worker
656*8975f5c5SAndroid Build Coastguard Worker    mDelegate = [[WindowDelegate alloc] initWithWindow:this];
657*8975f5c5SAndroid Build Coastguard Worker    if (mDelegate == nil)
658*8975f5c5SAndroid Build Coastguard Worker    {
659*8975f5c5SAndroid Build Coastguard Worker        return false;
660*8975f5c5SAndroid Build Coastguard Worker    }
661*8975f5c5SAndroid Build Coastguard Worker    [mWindow setDelegate:static_cast<id>(mDelegate)];
662*8975f5c5SAndroid Build Coastguard Worker
663*8975f5c5SAndroid Build Coastguard Worker    mView = [[ContentView alloc] initWithWindow:this];
664*8975f5c5SAndroid Build Coastguard Worker    if (mView == nil)
665*8975f5c5SAndroid Build Coastguard Worker    {
666*8975f5c5SAndroid Build Coastguard Worker        return false;
667*8975f5c5SAndroid Build Coastguard Worker    }
668*8975f5c5SAndroid Build Coastguard Worker    [mView setWantsLayer:YES];
669*8975f5c5SAndroid Build Coastguard Worker
670*8975f5c5SAndroid Build Coastguard Worker    // Disable scaling for this view. If scaling is enabled, the metal backend's
671*8975f5c5SAndroid Build Coastguard Worker    // frame buffer's size will be this window's size multiplied by contentScale.
672*8975f5c5SAndroid Build Coastguard Worker    // It will cause inconsistent testing & example apps' results.
673*8975f5c5SAndroid Build Coastguard Worker    mView.layer.contentsScale = 1;
674*8975f5c5SAndroid Build Coastguard Worker
675*8975f5c5SAndroid Build Coastguard Worker    [mWindow setContentView:mView];
676*8975f5c5SAndroid Build Coastguard Worker    [mWindow setTitle:[NSString stringWithUTF8String:name.c_str()]];
677*8975f5c5SAndroid Build Coastguard Worker    [mWindow setAcceptsMouseMovedEvents:YES];
678*8975f5c5SAndroid Build Coastguard Worker    [mWindow center];
679*8975f5c5SAndroid Build Coastguard Worker
680*8975f5c5SAndroid Build Coastguard Worker    [NSApp activateIgnoringOtherApps:YES];
681*8975f5c5SAndroid Build Coastguard Worker
682*8975f5c5SAndroid Build Coastguard Worker    mX      = 0;
683*8975f5c5SAndroid Build Coastguard Worker    mY      = 0;
684*8975f5c5SAndroid Build Coastguard Worker    mWidth  = width;
685*8975f5c5SAndroid Build Coastguard Worker    mHeight = height;
686*8975f5c5SAndroid Build Coastguard Worker
687*8975f5c5SAndroid Build Coastguard Worker    AllWindows().insert(this);
688*8975f5c5SAndroid Build Coastguard Worker    return true;
689*8975f5c5SAndroid Build Coastguard Worker}
690*8975f5c5SAndroid Build Coastguard Worker
691*8975f5c5SAndroid Build Coastguard Workervoid OSXWindow::disableErrorMessageDialog() {}
692*8975f5c5SAndroid Build Coastguard Worker
693*8975f5c5SAndroid Build Coastguard Workervoid OSXWindow::destroy()
694*8975f5c5SAndroid Build Coastguard Worker{
695*8975f5c5SAndroid Build Coastguard Worker    AllWindows().erase(this);
696*8975f5c5SAndroid Build Coastguard Worker
697*8975f5c5SAndroid Build Coastguard Worker    [mView release];
698*8975f5c5SAndroid Build Coastguard Worker    mView = nil;
699*8975f5c5SAndroid Build Coastguard Worker    [mDelegate onOSXWindowDeleted];
700*8975f5c5SAndroid Build Coastguard Worker    [mDelegate release];
701*8975f5c5SAndroid Build Coastguard Worker    mDelegate = nil;
702*8975f5c5SAndroid Build Coastguard Worker    // NSWindow won't be completely released unless its content view is set to nil:
703*8975f5c5SAndroid Build Coastguard Worker    [mWindow setContentView:nil];
704*8975f5c5SAndroid Build Coastguard Worker    [mWindow release];
705*8975f5c5SAndroid Build Coastguard Worker    mWindow = nil;
706*8975f5c5SAndroid Build Coastguard Worker}
707*8975f5c5SAndroid Build Coastguard Worker
708*8975f5c5SAndroid Build Coastguard Workervoid OSXWindow::resetNativeWindow() {}
709*8975f5c5SAndroid Build Coastguard Worker
710*8975f5c5SAndroid Build Coastguard WorkerEGLNativeWindowType OSXWindow::getNativeWindow() const
711*8975f5c5SAndroid Build Coastguard Worker{
712*8975f5c5SAndroid Build Coastguard Worker    return [mView layer];
713*8975f5c5SAndroid Build Coastguard Worker}
714*8975f5c5SAndroid Build Coastguard Worker
715*8975f5c5SAndroid Build Coastguard WorkerEGLNativeDisplayType OSXWindow::getNativeDisplay() const
716*8975f5c5SAndroid Build Coastguard Worker{
717*8975f5c5SAndroid Build Coastguard Worker    // TODO(cwallez): implement it once we have defined what EGLNativeDisplayType is
718*8975f5c5SAndroid Build Coastguard Worker    return static_cast<EGLNativeDisplayType>(0);
719*8975f5c5SAndroid Build Coastguard Worker}
720*8975f5c5SAndroid Build Coastguard Worker
721*8975f5c5SAndroid Build Coastguard Workervoid OSXWindow::messageLoop()
722*8975f5c5SAndroid Build Coastguard Worker{
723*8975f5c5SAndroid Build Coastguard Worker    @autoreleasepool
724*8975f5c5SAndroid Build Coastguard Worker    {
725*8975f5c5SAndroid Build Coastguard Worker        while (true)
726*8975f5c5SAndroid Build Coastguard Worker        {
727*8975f5c5SAndroid Build Coastguard Worker            // TODO(http://anglebug.com/42265067): @try/@catch is a workaround for
728*8975f5c5SAndroid Build Coastguard Worker            // exceptions being thrown from Cocoa-internal function
729*8975f5c5SAndroid Build Coastguard Worker            // NS_setFlushesWithDisplayLink starting in macOS 11.
730*8975f5c5SAndroid Build Coastguard Worker            @try
731*8975f5c5SAndroid Build Coastguard Worker            {
732*8975f5c5SAndroid Build Coastguard Worker                NSEvent *event = [NSApp nextEventMatchingMask:NSAnyEventMask
733*8975f5c5SAndroid Build Coastguard Worker                                                    untilDate:[NSDate distantPast]
734*8975f5c5SAndroid Build Coastguard Worker                                                       inMode:NSDefaultRunLoopMode
735*8975f5c5SAndroid Build Coastguard Worker                                                      dequeue:YES];
736*8975f5c5SAndroid Build Coastguard Worker                if (event == nil)
737*8975f5c5SAndroid Build Coastguard Worker                {
738*8975f5c5SAndroid Build Coastguard Worker                    break;
739*8975f5c5SAndroid Build Coastguard Worker                }
740*8975f5c5SAndroid Build Coastguard Worker
741*8975f5c5SAndroid Build Coastguard Worker                if ([event type] == NSAppKitDefined)
742*8975f5c5SAndroid Build Coastguard Worker                {
743*8975f5c5SAndroid Build Coastguard Worker                    continue;
744*8975f5c5SAndroid Build Coastguard Worker                }
745*8975f5c5SAndroid Build Coastguard Worker                [NSApp sendEvent:event];
746*8975f5c5SAndroid Build Coastguard Worker            }
747*8975f5c5SAndroid Build Coastguard Worker            @catch (NSException *localException)
748*8975f5c5SAndroid Build Coastguard Worker            {
749*8975f5c5SAndroid Build Coastguard Worker                NSLog(@"*** OSXWindow discarding exception: <%@> %@", [localException name],
750*8975f5c5SAndroid Build Coastguard Worker                      [localException reason]);
751*8975f5c5SAndroid Build Coastguard Worker            }
752*8975f5c5SAndroid Build Coastguard Worker        }
753*8975f5c5SAndroid Build Coastguard Worker    }
754*8975f5c5SAndroid Build Coastguard Worker}
755*8975f5c5SAndroid Build Coastguard Worker
756*8975f5c5SAndroid Build Coastguard Workervoid OSXWindow::setMousePosition(int x, int y)
757*8975f5c5SAndroid Build Coastguard Worker{
758*8975f5c5SAndroid Build Coastguard Worker    y = (int)([mWindow frame].size.height) - y - 1;
759*8975f5c5SAndroid Build Coastguard Worker    NSPoint screenspace;
760*8975f5c5SAndroid Build Coastguard Worker
761*8975f5c5SAndroid Build Coastguard Worker#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7
762*8975f5c5SAndroid Build Coastguard Worker    screenspace = [mWindow convertBaseToScreen:NSMakePoint(x, y)];
763*8975f5c5SAndroid Build Coastguard Worker#else
764*8975f5c5SAndroid Build Coastguard Worker    screenspace = [mWindow convertRectToScreen:NSMakeRect(x, y, 0, 0)].origin;
765*8975f5c5SAndroid Build Coastguard Worker#endif
766*8975f5c5SAndroid Build Coastguard Worker    CGWarpMouseCursorPosition(CGPointMake(screenspace.x, YCoordToFromCG(screenspace.y)));
767*8975f5c5SAndroid Build Coastguard Worker}
768*8975f5c5SAndroid Build Coastguard Worker
769*8975f5c5SAndroid Build Coastguard Workerbool OSXWindow::setOrientation(int width, int height)
770*8975f5c5SAndroid Build Coastguard Worker{
771*8975f5c5SAndroid Build Coastguard Worker    UNIMPLEMENTED();
772*8975f5c5SAndroid Build Coastguard Worker    return false;
773*8975f5c5SAndroid Build Coastguard Worker}
774*8975f5c5SAndroid Build Coastguard Worker
775*8975f5c5SAndroid Build Coastguard Workerbool OSXWindow::setPosition(int x, int y)
776*8975f5c5SAndroid Build Coastguard Worker{
777*8975f5c5SAndroid Build Coastguard Worker    // Given CG and NS's coordinate system, the "Y" position of a window is the Y coordinate
778*8975f5c5SAndroid Build Coastguard Worker    // of the bottom of the window.
779*8975f5c5SAndroid Build Coastguard Worker    int newBottom    = (int)([mWindow frame].size.height) + y;
780*8975f5c5SAndroid Build Coastguard Worker    NSRect emptyRect = NSMakeRect(x, YCoordToFromCG(newBottom), 0, 0);
781*8975f5c5SAndroid Build Coastguard Worker    [mWindow setFrameOrigin:[mWindow frameRectForContentRect:emptyRect].origin];
782*8975f5c5SAndroid Build Coastguard Worker    return true;
783*8975f5c5SAndroid Build Coastguard Worker}
784*8975f5c5SAndroid Build Coastguard Worker
785*8975f5c5SAndroid Build Coastguard Workerbool OSXWindow::resize(int width, int height)
786*8975f5c5SAndroid Build Coastguard Worker{
787*8975f5c5SAndroid Build Coastguard Worker    [mWindow setContentSize:NSMakeSize(width, height)];
788*8975f5c5SAndroid Build Coastguard Worker    return true;
789*8975f5c5SAndroid Build Coastguard Worker}
790*8975f5c5SAndroid Build Coastguard Worker
791*8975f5c5SAndroid Build Coastguard Workervoid OSXWindow::setVisible(bool isVisible)
792*8975f5c5SAndroid Build Coastguard Worker{
793*8975f5c5SAndroid Build Coastguard Worker    if (isVisible)
794*8975f5c5SAndroid Build Coastguard Worker    {
795*8975f5c5SAndroid Build Coastguard Worker        [mWindow makeKeyAndOrderFront:nil];
796*8975f5c5SAndroid Build Coastguard Worker    }
797*8975f5c5SAndroid Build Coastguard Worker    else
798*8975f5c5SAndroid Build Coastguard Worker    {
799*8975f5c5SAndroid Build Coastguard Worker        [mWindow orderOut:nil];
800*8975f5c5SAndroid Build Coastguard Worker    }
801*8975f5c5SAndroid Build Coastguard Worker}
802*8975f5c5SAndroid Build Coastguard Worker
803*8975f5c5SAndroid Build Coastguard Workervoid OSXWindow::signalTestEvent()
804*8975f5c5SAndroid Build Coastguard Worker{
805*8975f5c5SAndroid Build Coastguard Worker    @autoreleasepool
806*8975f5c5SAndroid Build Coastguard Worker    {
807*8975f5c5SAndroid Build Coastguard Worker        NSEvent *event = [NSEvent otherEventWithType:NSApplicationDefined
808*8975f5c5SAndroid Build Coastguard Worker                                            location:NSMakePoint(0, 0)
809*8975f5c5SAndroid Build Coastguard Worker                                       modifierFlags:0
810*8975f5c5SAndroid Build Coastguard Worker                                           timestamp:0.0
811*8975f5c5SAndroid Build Coastguard Worker                                        windowNumber:[mWindow windowNumber]
812*8975f5c5SAndroid Build Coastguard Worker                                             context:nil
813*8975f5c5SAndroid Build Coastguard Worker                                             subtype:0
814*8975f5c5SAndroid Build Coastguard Worker                                               data1:0
815*8975f5c5SAndroid Build Coastguard Worker                                               data2:0];
816*8975f5c5SAndroid Build Coastguard Worker        [NSApp postEvent:event atStart:YES];
817*8975f5c5SAndroid Build Coastguard Worker    }
818*8975f5c5SAndroid Build Coastguard Worker}
819*8975f5c5SAndroid Build Coastguard Worker
820*8975f5c5SAndroid Build Coastguard WorkerNSWindow *OSXWindow::getNSWindow() const
821*8975f5c5SAndroid Build Coastguard Worker{
822*8975f5c5SAndroid Build Coastguard Worker    return mWindow;
823*8975f5c5SAndroid Build Coastguard Worker}
824*8975f5c5SAndroid Build Coastguard Worker
825*8975f5c5SAndroid Build Coastguard Worker// static
826*8975f5c5SAndroid Build Coastguard WorkerOSWindow *OSWindow::New()
827*8975f5c5SAndroid Build Coastguard Worker{
828*8975f5c5SAndroid Build Coastguard Worker    return new OSXWindow;
829*8975f5c5SAndroid Build Coastguard Worker}
830