bool COSXScreen::onKey(CGEventRef event) { CGEventType eventKind = CGEventGetType(event); // get the key and active modifiers UInt32 virtualKey = CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode); CGEventFlags macMask = CGEventGetFlags(event); LOG((CLOG_DEBUG1 "event: Key event kind: %d, keycode=%d", eventKind, virtualKey)); // Special handling to track state of modifiers if (eventKind == kCGEventFlagsChanged) { // get old and new modifier state KeyModifierMask oldMask = getActiveModifiers(); KeyModifierMask newMask = m_keyState->mapModifiersFromOSX(macMask); m_keyState->handleModifierKeys(getEventTarget(), oldMask, newMask); // if the current set of modifiers exactly matches a modifiers-only // hot key then generate a hot key down event. if (m_activeModifierHotKey == 0) { if (m_modifierHotKeys.count(newMask) > 0) { m_activeModifierHotKey = m_modifierHotKeys[newMask]; m_activeModifierHotKeyMask = newMask; m_events->addEvent(CEvent(m_events->forIPrimaryScreen().hotKeyDown(), getEventTarget(), CHotKeyInfo::alloc(m_activeModifierHotKey))); } } // if a modifiers-only hot key is active and should no longer be // then generate a hot key up event. else if (m_activeModifierHotKey != 0) { KeyModifierMask mask = (newMask & m_activeModifierHotKeyMask); if (mask != m_activeModifierHotKeyMask) { m_events->addEvent(CEvent(m_events->forIPrimaryScreen().hotKeyUp(), getEventTarget(), CHotKeyInfo::alloc(m_activeModifierHotKey))); m_activeModifierHotKey = 0; m_activeModifierHotKeyMask = 0; } } return true; } // check for hot key. when we're on a secondary screen we disable // all hotkeys so we can capture the OS defined hot keys as regular // keystrokes but that means we don't get our own hot keys either. // so we check for a key/modifier match in our hot key map. if (!m_isOnScreen) { HotKeyToIDMap::const_iterator i = m_hotKeyToIDMap.find(CHotKeyItem(virtualKey, m_keyState->mapModifiersToCarbon(macMask) & 0xff00u)); if (i != m_hotKeyToIDMap.end()) { UInt32 id = i->second; // determine event type CEvent::Type type; //UInt32 eventKind = GetEventKind(event); if (eventKind == kCGEventKeyDown) { type = m_events->forIPrimaryScreen().hotKeyDown(); } else if (eventKind == kCGEventKeyUp) { type = m_events->forIPrimaryScreen().hotKeyUp(); } else { return false; } m_events->addEvent(CEvent(type, getEventTarget(), CHotKeyInfo::alloc(id))); return true; } } // decode event type bool down = (eventKind == kCGEventKeyDown); bool up = (eventKind == kCGEventKeyUp); bool isRepeat = (CGEventGetIntegerValueField(event, kCGKeyboardEventAutorepeat) == 1); // map event to keys KeyModifierMask mask; COSXKeyState::CKeyIDs keys; KeyButton button = m_keyState->mapKeyFromEvent(keys, &mask, event); if (button == 0) { return false; } // check for AltGr in mask. if set we send neither the AltGr nor // the super modifiers to clients then remove AltGr before passing // the modifiers to onKey. KeyModifierMask sendMask = (mask & ~KeyModifierAltGr); if ((mask & KeyModifierAltGr) != 0) { sendMask &= ~KeyModifierSuper; } mask &= ~KeyModifierAltGr; // update button state if (down) { m_keyState->onKey(button, true, mask); } else if (up) { if (!m_keyState->isKeyDown(button)) { // up event for a dead key. throw it away. return false; } m_keyState->onKey(button, false, mask); } // send key events for (COSXKeyState::CKeyIDs::const_iterator i = keys.begin(); i != keys.end(); ++i) { m_keyState->sendKeyEvent(getEventTarget(), down, isRepeat, *i, sendMask, 1, button); } return true; }
bool COSXScreen::onKey(EventRef event) { UInt32 eventKind = GetEventKind(event); // get the key and active modifiers UInt32 virtualKey, macMask; GetEventParameter(event, kEventParamKeyCode, typeUInt32, NULL, sizeof(virtualKey), NULL, &virtualKey); GetEventParameter(event, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(macMask), NULL, &macMask); LOG((CLOG_DEBUG1 "event: Key event kind: %d, keycode=%d", eventKind, virtualKey)); // sadly, OS X doesn't report the virtualKey for modifier keys. // virtualKey will be zero for modifier keys. since that's not good // enough we'll have to figure out what the key was. if (virtualKey == 0 && eventKind == kEventRawKeyModifiersChanged) { // get old and new modifier state KeyModifierMask oldMask = getActiveModifiers(); KeyModifierMask newMask = m_keyState->mapModifiersFromOSX(macMask); m_keyState->handleModifierKeys(getEventTarget(), oldMask, newMask); // if the current set of modifiers exactly matches a modifiers-only // hot key then generate a hot key down event. if (m_activeModifierHotKey == 0) { if (m_modifierHotKeys.count(newMask) > 0) { m_activeModifierHotKey = m_modifierHotKeys[newMask]; m_activeModifierHotKeyMask = newMask; EVENTQUEUE->addEvent(CEvent(getHotKeyDownEvent(), getEventTarget(), CHotKeyInfo::alloc(m_activeModifierHotKey))); } } // if a modifiers-only hot key is active and should no longer be // then generate a hot key up event. else if (m_activeModifierHotKey != 0) { KeyModifierMask mask = (newMask & m_activeModifierHotKeyMask); if (mask != m_activeModifierHotKeyMask) { EVENTQUEUE->addEvent(CEvent(getHotKeyUpEvent(), getEventTarget(), CHotKeyInfo::alloc(m_activeModifierHotKey))); m_activeModifierHotKey = 0; m_activeModifierHotKeyMask = 0; } } return true; } // check for hot key. when we're on a secondary screen we disable // all hotkeys so we can capture the OS defined hot keys as regular // keystrokes but that means we don't get our own hot keys either. // so we check for a key/modifier match in our hot key map. if (!m_isOnScreen) { HotKeyToIDMap::const_iterator i = m_hotKeyToIDMap.find(CHotKeyItem(virtualKey, macMask & 0xff00u)); if (i != m_hotKeyToIDMap.end()) { UInt32 id = i->second; // determine event type CEvent::Type type; UInt32 eventKind = GetEventKind(event); if (eventKind == kEventRawKeyDown) { type = getHotKeyDownEvent(); } else if (eventKind == kEventRawKeyUp) { type = getHotKeyUpEvent(); } else { return false; } EVENTQUEUE->addEvent(CEvent(type, getEventTarget(), CHotKeyInfo::alloc(id))); return true; } } // decode event type bool down = (eventKind == kEventRawKeyDown); bool up = (eventKind == kEventRawKeyUp); bool isRepeat = (eventKind == kEventRawKeyRepeat); // map event to keys KeyModifierMask mask; COSXKeyState::CKeyIDs keys; KeyButton button = m_keyState->mapKeyFromEvent(keys, &mask, event); if (button == 0) { return false; } // check for AltGr in mask. if set we send neither the AltGr nor // the super modifiers to clients then remove AltGr before passing // the modifiers to onKey. KeyModifierMask sendMask = (mask & ~KeyModifierAltGr); if ((mask & KeyModifierAltGr) != 0) { sendMask &= ~KeyModifierSuper; } mask &= ~KeyModifierAltGr; // update button state if (down) { m_keyState->onKey(button, true, mask); } else if (up) { if (!m_keyState->isKeyDown(button)) { // up event for a dead key. throw it away. return false; } m_keyState->onKey(button, false, mask); } // send key events for (COSXKeyState::CKeyIDs::const_iterator i = keys.begin(); i != keys.end(); ++i) { m_keyState->sendKeyEvent(getEventTarget(), down, isRepeat, *i, sendMask, 1, button); } return true; }