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; }
KeyButton OSXKeyState::mapKeyFromEvent(KeyIDs& ids, KeyModifierMask* maskOut, CGEventRef event) const { ids.clear(); // map modifier key if (maskOut != NULL) { KeyModifierMask activeMask = getActiveModifiers(); activeMask &= ~KeyModifierAltGr; *maskOut = activeMask; } // get virtual key UInt32 vkCode = CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode); // handle up events UInt32 eventKind = CGEventGetType(event); if (eventKind == kCGEventKeyUp) { // the id isn't used. we just need the same button we used on // the key press. note that we don't use or reset the dead key // state; up events should not affect the dead key state. ids.push_back(kKeyNone); return mapVirtualKeyToKeyButton(vkCode); } // check for special keys VirtualKeyMap::const_iterator i = m_virtualKeyMap.find(vkCode); if (i != m_virtualKeyMap.end()) { m_deadKeyState = 0; ids.push_back(i->second); return mapVirtualKeyToKeyButton(vkCode); } // get keyboard info #if defined(MAC_OS_X_VERSION_10_5) TISInputSourceRef currentKeyboardLayout = TISCopyCurrentKeyboardLayoutInputSource(); #else KeyboardLayoutRef currentKeyboardLayout; OSStatus status = KLGetCurrentKeyboardLayout(¤tKeyboardLayout); #endif if (currentKeyboardLayout == NULL) { return kKeyNone; } // get the event modifiers and remove the command and control // keys. note if we used them though. // UCKeyTranslate expects old-style Carbon modifiers, so convert. UInt32 modifiers; modifiers = mapModifiersToCarbon(CGEventGetFlags(event)); static const UInt32 s_commandModifiers = cmdKey | controlKey | rightControlKey; bool isCommand = ((modifiers & s_commandModifiers) != 0); modifiers &= ~s_commandModifiers; // if we've used a command key then we want the glyph produced without // the option key (i.e. the base glyph). //if (isCommand) { modifiers &= ~optionKey; //} // choose action UInt16 action; if(eventKind==kCGEventKeyDown) { action = kUCKeyActionDown; } else if(CGEventGetIntegerValueField(event, kCGKeyboardEventAutorepeat)==1) { action = kUCKeyActionAutoKey; } else { return 0; } // translate via uchr resource #if defined(MAC_OS_X_VERSION_10_5) CFDataRef ref = (CFDataRef) TISGetInputSourceProperty(currentKeyboardLayout, kTISPropertyUnicodeKeyLayoutData); const UCKeyboardLayout* layout = (const UCKeyboardLayout*) CFDataGetBytePtr(ref); const bool layoutValid = (layout != NULL); #else const void* resource; int err = KLGetKeyboardLayoutProperty(currentKeyboardLayout, kKLuchrData, &resource); const bool layoutValid = (err == noErr); const UCKeyboardLayout* layout = (const UCKeyboardLayout*)resource; #endif if (layoutValid) { // translate key UniCharCount count; UniChar chars[2]; LOG((CLOG_DEBUG2 "modifiers: %08x", modifiers & 0xffu)); OSStatus status = UCKeyTranslate(layout, vkCode & 0xffu, action, (modifiers >> 8) & 0xffu, LMGetKbdType(), 0, &m_deadKeyState, sizeof(chars) / sizeof(chars[0]), &count, chars); // get the characters if (status == 0) { if (count != 0 || m_deadKeyState == 0) { m_deadKeyState = 0; for (UniCharCount i = 0; i < count; ++i) { ids.push_back(KeyResource::unicharToKeyID(chars[i])); } adjustAltGrModifier(ids, maskOut, isCommand); return mapVirtualKeyToKeyButton(vkCode); } return 0; } } return 0; }