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