diff --git a/examples/common/entry/entry_osx.mm b/examples/common/entry/entry_osx.mm index 9c48e32c..d0f9c088 100644 --- a/examples/common/entry/entry_osx.mm +++ b/examples/common/entry/entry_osx.mm @@ -126,8 +126,18 @@ } @end +// Scan codes on Mac taken from http://boredzo.org/blog/archives/2007-05-22/virtual-key-codes + +#define KEY_RETURN 36 +#define KEY_TAB 48 +#define KEY_DELETE 51 +#define KEY_ESCAPE 53 + namespace entry { + static WindowHandle s_defaultWindow = { 0 }; // TODO: Add support for more windows + static uint8_t s_translateKey[256]; + struct MainThreadEntry { int m_argc; @@ -145,6 +155,106 @@ namespace entry Context() : m_exit(false) { + s_translateKey[KEY_ESCAPE] = Key::Esc; + s_translateKey[KEY_RETURN] = Key::Return; + s_translateKey[KEY_TAB] = Key::Tab; + s_translateKey[KEY_DELETE] = Key::Backspace; + //s_translateKey[VK_SPACE] = Key::Space; + //s_translateKey[VK_UP] = Key::Up; + //s_translateKey[VK_DOWN] = Key::Down; + //s_translateKey[VK_LEFT] = Key::Left; + //s_translateKey[VK_RIGHT] = Key::Right; + //s_translateKey[VK_PRIOR] = Key::PageUp; + //s_translateKey[VK_NEXT] = Key::PageUp; + //s_translateKey[VK_HOME] = Key::Home; + //s_translateKey[VK_END] = Key::End; + //s_translateKey[VK_SNAPSHOT] = Key::Print; + //s_translateKey[VK_OEM_PLUS] = Key::Plus; + //s_translateKey[VK_OEM_MINUS] = Key::Minus; + //s_translateKey[VK_F1] = Key::F1; + //s_translateKey[VK_F2] = Key::F2; + //s_translateKey[VK_F3] = Key::F3; + //s_translateKey[VK_F4] = Key::F4; + //s_translateKey[VK_F5] = Key::F5; + //s_translateKey[VK_F6] = Key::F6; + //s_translateKey[VK_F7] = Key::F7; + //s_translateKey[VK_F8] = Key::F8; + //s_translateKey[VK_F9] = Key::F9; + //s_translateKey[VK_F10] = Key::F10; + //s_translateKey[VK_F11] = Key::F11; + //s_translateKey[VK_F12] = Key::F12; + //s_translateKey[VK_NUMPAD0] = Key::NumPad0; + //s_translateKey[VK_NUMPAD1] = Key::NumPad1; + //s_translateKey[VK_NUMPAD2] = Key::NumPad2; + //s_translateKey[VK_NUMPAD3] = Key::NumPad3; + //s_translateKey[VK_NUMPAD4] = Key::NumPad4; + //s_translateKey[VK_NUMPAD5] = Key::NumPad5; + //s_translateKey[VK_NUMPAD6] = Key::NumPad6; + //s_translateKey[VK_NUMPAD7] = Key::NumPad7; + //s_translateKey[VK_NUMPAD8] = Key::NumPad8; + //s_translateKey[VK_NUMPAD9] = Key::NumPad9; + s_translateKey['0'] = Key::Key0; + s_translateKey['1'] = Key::Key1; + s_translateKey['2'] = Key::Key2; + s_translateKey['3'] = Key::Key3; + s_translateKey['4'] = Key::Key4; + s_translateKey['5'] = Key::Key5; + s_translateKey['6'] = Key::Key6; + s_translateKey['7'] = Key::Key7; + s_translateKey['8'] = Key::Key8; + s_translateKey['9'] = Key::Key9; + s_translateKey['A'] = Key::KeyA; + s_translateKey['B'] = Key::KeyB; + s_translateKey['C'] = Key::KeyC; + s_translateKey['D'] = Key::KeyD; + s_translateKey['E'] = Key::KeyE; + s_translateKey['F'] = Key::KeyF; + s_translateKey['G'] = Key::KeyG; + s_translateKey['H'] = Key::KeyH; + s_translateKey['I'] = Key::KeyI; + s_translateKey['J'] = Key::KeyJ; + s_translateKey['K'] = Key::KeyK; + s_translateKey['L'] = Key::KeyL; + s_translateKey['M'] = Key::KeyM; + s_translateKey['N'] = Key::KeyN; + s_translateKey['O'] = Key::KeyO; + s_translateKey['P'] = Key::KeyP; + s_translateKey['Q'] = Key::KeyQ; + s_translateKey['R'] = Key::KeyR; + s_translateKey['S'] = Key::KeyS; + s_translateKey['T'] = Key::KeyT; + s_translateKey['U'] = Key::KeyU; + s_translateKey['V'] = Key::KeyV; + s_translateKey['W'] = Key::KeyW; + s_translateKey['X'] = Key::KeyX; + s_translateKey['Y'] = Key::KeyY; + s_translateKey['Z'] = Key::KeyZ; + s_translateKey['a'] = Key::KeyA; + s_translateKey['b'] = Key::KeyB; + s_translateKey['c'] = Key::KeyC; + s_translateKey['d'] = Key::KeyD; + s_translateKey['e'] = Key::KeyE; + s_translateKey['f'] = Key::KeyF; + s_translateKey['g'] = Key::KeyG; + s_translateKey['h'] = Key::KeyH; + s_translateKey['i'] = Key::KeyI; + s_translateKey['j'] = Key::KeyJ; + s_translateKey['k'] = Key::KeyK; + s_translateKey['l'] = Key::KeyL; + s_translateKey['m'] = Key::KeyM; + s_translateKey['n'] = Key::KeyN; + s_translateKey['o'] = Key::KeyO; + s_translateKey['p'] = Key::KeyP; + s_translateKey['q'] = Key::KeyQ; + s_translateKey['r'] = Key::KeyR; + s_translateKey['s'] = Key::KeyS; + s_translateKey['t'] = Key::KeyT; + s_translateKey['u'] = Key::KeyU; + s_translateKey['v'] = Key::KeyV; + s_translateKey['w'] = Key::KeyW; + s_translateKey['x'] = Key::KeyX; + s_translateKey['y'] = Key::KeyY; + s_translateKey['z'] = Key::KeyZ; } NSEvent* waitEvent() @@ -167,12 +277,167 @@ namespace entry ]; } + void getMousePos(int* outX, int* outY) + { + NSRect originalFrame = [m_window frame]; + NSPoint location = [m_window mouseLocationOutsideOfEventStream]; + NSRect adjustFrame = [NSWindow contentRectForFrameRect: originalFrame styleMask: NSTitledWindowMask]; + + int x = location.x; + int y = (int)adjustFrame.size.height - (int)location.y; + + // clamp within the range of the window + + if (x < 0) x = 0; + if (y < 0) y = 0; + if (x > (int)adjustFrame.size.width) x = (int)adjustFrame.size.width; + if (y > (int)adjustFrame.size.height) y = (int)adjustFrame.size.height; + + *outX = x; + *outY = y; + } + + uint8_t translateModifiers(int flags) + { + uint8_t mask = 0; + + if (flags & NSShiftKeyMask) + mask |= Modifier::LeftShift | Modifier::RightShift; + + if (flags & NSAlternateKeyMask) + mask |= Modifier::LeftAlt | Modifier::RightAlt; + + if (flags & NSControlKeyMask) + mask |= Modifier::LeftCtrl | Modifier::RightCtrl; + + if (flags & NSCommandKeyMask) + mask |= Modifier::LeftMeta | Modifier::RightMeta; + + return mask; + } + + Key::Enum handleKeyEvent(NSEvent* event, uint8_t* specialKeys) + { + NSString* key = [event charactersIgnoringModifiers]; + unichar keyChar = 0; + if ([key length] == 0) + return Key::None; + + keyChar = [key characterAtIndex:0]; + + int keyCode = keyChar; + *specialKeys = translateModifiers([event modifierFlags]); + + // if this is a unhandled key just return None + + if (keyCode >= 256) + return Key::None; + + return (Key::Enum)s_translateKey[keyCode]; + } + bool dispatchEvent(NSEvent* event) { if (event) { + NSEventType eventType = [event type]; + + switch (eventType) + { + case NSMouseMoved : + { + int x, y; + + getMousePos(&x, &y); + + m_eventQueue.postMouseEvent(s_defaultWindow, x, y, 0); + + break; + } + + case NSLeftMouseDown: + { + int x, y; + + getMousePos(&x, &y); + + m_eventQueue.postMouseEvent(s_defaultWindow, x, y, 0, MouseButton::Left, true); + + break; + } + + case NSLeftMouseUp: + { + int x, y; + + getMousePos(&x, &y); + + m_eventQueue.postMouseEvent(s_defaultWindow, x, y, 0, MouseButton::Left, false); + + break; + } + + case NSRightMouseDown: + { + int x, y; + + getMousePos(&x, &y); + + m_eventQueue.postMouseEvent(s_defaultWindow, x, y, 0, MouseButton::Right, true); + + break; + } + + case NSRightMouseUp: + { + int x, y; + + getMousePos(&x, &y); + + m_eventQueue.postMouseEvent(s_defaultWindow, x, y, 0, MouseButton::Right, false); + + break; + } + + case NSKeyDown: + { + uint8_t modifiers = 0; + Key::Enum key = handleKeyEvent(event, &modifiers); + + // If KeyCode is none we don't don't handle the key and special case for cmd+q (quit) + // Note that return false here means that we take care of the key (instead of the default behavior) + + if (key != Key::None) + { + if (key != Key::KeyQ && !((modifiers & Modifier::RightMeta))) + { + m_eventQueue.postKeyEvent(s_defaultWindow, key, modifiers, true); + return false; + } + } + + break; + } + + case NSKeyUp: + { + uint8_t modifiers = 0; + Key::Enum key = handleKeyEvent(event, &modifiers); + + if (key != Key::None) + { + m_eventQueue.postKeyEvent(s_defaultWindow, key, modifiers, false); + return false; + } + + break; + } + } + + [NSApp sendEvent:event]; [NSApp updateWindows]; + return true; } @@ -229,9 +494,12 @@ namespace entry [window cascadeTopLeftFromPoint:NSMakePoint(20,20)]; [window makeKeyAndOrderFront:window]; // [window setContentView:nil]; + [window setAcceptsMouseMovedEvents:YES]; [window setBackgroundColor:[NSColor blackColor]]; [[Window sharedDelegate] windowCreated:window]; + m_window = window; + bgfx::osxSetNSWindow(window); MainThreadEntry mte; @@ -265,6 +533,7 @@ namespace entry EventQueue m_eventQueue; bool m_exit; + NSWindow* m_window; }; static Context s_ctx;