void COSXKeyState::adjustAltGrModifier(const CKeyIDs& ids, KeyModifierMask* mask, bool isCommand) const { if (!isCommand) { for (CKeyIDs::const_iterator i = ids.begin(); i != ids.end(); ++i) { KeyID id = *i; if (id != kKeyNone && ((id < 0xe000u || id > 0xefffu) || (id >= kKeyKP_Equal && id <= kKeyKP_9))) { *mask |= KeyModifierAltGr; return; } } } }
KeyButton COSXKeyState::mapKeyFromEvent(CKeyIDs& ids, KeyModifierMask* maskOut, EventRef event) const { ids.clear(); // map modifier key if (maskOut != NULL) { KeyModifierMask activeMask = getActiveModifiers(); activeMask &= ~KeyModifierAltGr; *maskOut = activeMask; } // get virtual key UInt32 vkCode; GetEventParameter(event, kEventParamKeyCode, typeUInt32, NULL, sizeof(vkCode), NULL, &vkCode); // handle up events UInt32 eventKind = GetEventKind(event); if (eventKind == kEventRawKeyUp) { // 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 CVirtualKeyMap::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 KeyboardLayoutRef keyboardLayout; OSStatus status = KLGetCurrentKeyboardLayout(&keyboardLayout); if (status != noErr) { return kKeyNone; } // get the event modifiers and remove the command and control // keys. note if we used them though. UInt32 modifiers; GetEventParameter(event, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(modifiers), NULL, &modifiers); 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; } // translate via uchr resource const void* resource; if (KLGetKeyboardLayoutProperty(keyboardLayout, kKLuchrData, &resource) == noErr) { // choose action UInt16 action; switch (eventKind) { case kEventRawKeyDown: action = kUCKeyActionDown; break; case kEventRawKeyRepeat: action = kUCKeyActionAutoKey; break; default: return 0; } // translate key UniCharCount count; UniChar chars[2]; OSStatus status = UCKeyTranslate((const UCKeyboardLayout*)resource, 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(CKeyResource::unicharToKeyID(chars[i])); } adjustAltGrModifier(ids, maskOut, isCommand); return mapVirtualKeyToKeyButton(vkCode); } return 0; } }
KeyButton COSXKeyState::mapKeyFromEvent(CKeyIDs& 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 CVirtualKeyMap::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(CKeyResource::unicharToKeyID(chars[i])); } adjustAltGrModifier(ids, maskOut, isCommand); return mapVirtualKeyToKeyButton(vkCode); } return 0; } } return 0; }