static UniChar OSKeyCodeToUnicode( UInt16 osKeyCode, bool shift = false )
{
    // Translate the key code.

    UniChar uniChar = 0;
    if( sKeyLayoutKind == kKLKCHRKind )
    {
        // KCHR mapping.

        void* KCHRData;
        KLGetKeyboardLayoutProperty( sKeyLayout, kKLKCHRData, ( const void** ) & KCHRData );

        UInt16 key = ( osKeyCode & 0x7f );
        if( shift )
            key |= NSShiftKeyMask;

        UInt32 keyTranslateState = 0;
        UInt32 charCode = KeyTranslate( KCHRData, key, &keyTranslateState );
        charCode &= 0xff;

        if( keyTranslateState == 0 && charCode )
            uniChar = charCode;
    }
    else
    {
        // UCHR mapping.

        UCKeyboardLayout* uchrData;
        KLGetKeyboardLayoutProperty( sKeyLayout, kKLuchrData, ( const void** ) &uchrData );

        UInt32 deadKeyState;
        UniCharCount actualStringLength;
        UniChar unicodeString[ 4 ];
        UCKeyTranslate( uchrData,
                        osKeyCode,
                        kUCKeyActionDown,
                        ( shift ? 0x02 : 0 ), // Oh yeah... Apple docs are fun...
                        LMGetKbdType(),
                        0,
                        &deadKeyState,
                        sizeof( unicodeString ) / sizeof( unicodeString[ 0 ] ),
                        &actualStringLength,
                        unicodeString );

        if( actualStringLength )
            uniChar = unicodeString[ 0 ]; // Well, Unicode is something else, but...
    }

    return uniChar;
}
Esempio n. 2
0
QString TranslateKey(quint8 vk)
{
    TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource();
    const CFDataRef layoutData = 
        reinterpret_cast<const CFDataRef>(TISGetInputSourceProperty(currentKeyboard,
                                          kTISPropertyUnicodeKeyLayoutData) );

    const UCKeyboardLayout *keyboardLayout =
        reinterpret_cast<const UCKeyboardLayout*>(CFDataGetBytePtr(layoutData));

    UInt32 keysDown = 0;
    UniChar chars[10];
    UniCharCount realLength = 0;

    OSStatus oss = UCKeyTranslate(keyboardLayout,
                                  vk,
                                  kUCKeyActionDown,
                                  0,
                                  LMGetKbdType(),
                                  0,//kUCKeyTranslateNoDeadKeysBit,
                                  &keysDown,
                                  sizeof(chars) / sizeof(chars[0]),
                                  &realLength,
                                  chars);
    Q_ASSERT(oss == 0);

    CFStringRef ptr_str = CFStringCreateWithCharacters(kCFAllocatorDefault, 
                                                       chars, (int)realLength);
    QString ss = QCFStringToQString(ptr_str);
    CFRelease(ptr_str);
    CFRelease(currentKeyboard);
    return ss;
}
KeySym HelperMacX::keycodeToKeysym(uint keycode){
	TISInputSourceRef inputSourceRef = TISCopyCurrentKeyboardInputSource();
	if (NULL == inputSourceRef) {
		qWarning("HelperMacX::keycodeToKeysym: inputSourceRef is NULL");
		return NoSymbol;
	}
	CFDataRef unicodeKeyLayoutDataRef = (CFDataRef)TISGetInputSourceProperty(inputSourceRef,
		kTISPropertyUnicodeKeyLayoutData);
	if (NULL == unicodeKeyLayoutDataRef) {
		CFRelease(inputSourceRef);
		qWarning("HelperMacX::keycodeToKeysym: unicodeKeyLayoutDataRef is NULL");
		return NoSymbol;
	}
	UCKeyboardLayout *unicodeKeyLayoutDataPtr = (UCKeyboardLayout*)CFDataGetBytePtr(unicodeKeyLayoutDataRef);
	UInt32 deadKeyState = 0;
	UniChar unicodeString[8];
	UniCharCount len = 0;
	OSStatus status = UCKeyTranslate(unicodeKeyLayoutDataPtr, keycode, kUCKeyActionDown,
									 0, LMGetKbdType(), kUCKeyTranslateNoDeadKeysMask,
									 &deadKeyState, sizeof(unicodeString), &len, unicodeString);
	CFRelease(inputSourceRef);
	if (noErr != status) {
		qWarning("HelperMacX::keycodeToKeysym: UCKeyTranslate error: %d", (int)status);
		return NoSymbol;
	}
	return 1 != len ? NoSymbol : unicodeString[0];
}
Esempio n. 4
0
/* Returns string representation of key, if it is printable.
 * Ownership follows the Create Rule; that is, it is the caller's
 * responsibility to release the returned object. */
CFStringRef createStringForKey(CGKeyCode keyCode)
{
    TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource();
    CFDataRef layoutData =
      (CFDataRef)TISGetInputSourceProperty(currentKeyboard,
                                  kTISPropertyUnicodeKeyLayoutData);
    const UCKeyboardLayout *keyboardLayout =
        (const UCKeyboardLayout *)CFDataGetBytePtr(layoutData);

    UInt32 keysDown = 0;
    UniChar chars[4];
    UniCharCount realLength;

    UCKeyTranslate(keyboardLayout,
                   keyCode,
                   kUCKeyActionDisplay,
                   0,
                   LMGetKbdType(),
                   kUCKeyTranslateNoDeadKeysBit,
                   &keysDown,
                   sizeof(chars) / sizeof(chars[0]),
                   &realLength,
                   chars);
    CFRelease(currentKeyboard);    

    return CFStringCreateWithCharacters(kCFAllocatorDefault, chars, 1);
}
Esempio n. 5
0
File: keys.cpp Progetto: JakimLi/kwm
internal CFStringRef
KeycodeToString(CGKeyCode Keycode)
{
    TISInputSourceRef Keyboard = TISCopyCurrentASCIICapableKeyboardLayoutInputSource();
    CFDataRef Uchr = (CFDataRef)TISGetInputSourceProperty(Keyboard, kTISPropertyUnicodeKeyLayoutData);
    const UCKeyboardLayout *KeyboardLayout = (const UCKeyboardLayout*)CFDataGetBytePtr(Uchr);

    if(KeyboardLayout)
    {
        UInt32 DeadKeyState = 0;
        UniCharCount MaxStringLength = 255;
        UniCharCount ActualStringLength = 0;
        UniChar UnicodeString[MaxStringLength];

        OSStatus Status = UCKeyTranslate(KeyboardLayout, Keycode,
                                         kUCKeyActionDown, 0,
                                         LMGetKbdType(), 0,
                                         &DeadKeyState,
                                         MaxStringLength,
                                         &ActualStringLength,
                                         UnicodeString);

        if (ActualStringLength == 0 && DeadKeyState)
        {
            Status = UCKeyTranslate(KeyboardLayout, kVK_Space,
                                    kUCKeyActionDown, 0,
                                    LMGetKbdType(), 0,
                                    &DeadKeyState,
                                    MaxStringLength,
                                    &ActualStringLength,
                                    UnicodeString);
        }

        if(ActualStringLength > 0 && Status == noErr)
            return CFStringCreateWithCharacters(NULL, UnicodeString, ActualStringLength);
    }

    return NULL;
}
Esempio n. 6
0
static PyObject *Evt_LMGetKbdType(PyObject *_self, PyObject *_args)
{
    PyObject *_res = NULL;
    UInt8 _rv;
#ifndef LMGetKbdType
    PyMac_PRECHECK(LMGetKbdType);
#endif
    if (!PyArg_ParseTuple(_args, ""))
        return NULL;
    _rv = LMGetKbdType();
    _res = Py_BuildValue("b",
                         _rv);
    return _res;
}
Esempio n. 7
0
void
OSXKeyState::getKeyMap(synergy::KeyMap& keyMap)
{
	// update keyboard groups
	if (getGroups(m_groups)) {
		m_groupMap.clear();
		SInt32 numGroups = (SInt32)m_groups.size();
		for (SInt32 g = 0; g < numGroups; ++g) {
			m_groupMap[m_groups[g]] = g;
		}
	}

	UInt32 keyboardType = LMGetKbdType();
	for (SInt32 g = 0, n = (SInt32)m_groups.size(); g < n; ++g) {
		// add special keys
		getKeyMapForSpecialKeys(keyMap, g);

		const void* resource;
		bool layoutValid = false;
		
		// add regular keys
		// try uchr resource first
		#if defined(MAC_OS_X_VERSION_10_5)
		CFDataRef resourceRef = (CFDataRef)TISGetInputSourceProperty(
			m_groups[g], kTISPropertyUnicodeKeyLayoutData);
		layoutValid = resourceRef != NULL;
		if (layoutValid)
			resource = CFDataGetBytePtr(resourceRef);
		#else
		layoutValid = KLGetKeyboardLayoutProperty(
			m_groups[g], kKLuchrData, &resource);
		#endif

		if (layoutValid) {
			CUCHRKeyResource uchr(resource, keyboardType);
			if (uchr.isValid()) {
				LOG((CLOG_DEBUG1 "using uchr resource for group %d", g));
				getKeyMap(keyMap, g, uchr);
				continue;
			}
		}

		LOG((CLOG_DEBUG1 "no keyboard resource for group %d", g));
	}
}
// Modified from NESControllerInterface of Macifom project,
// used under MIT license from http://macifom.googlecode.com/svn-history/r89/Macifom/trunk/NESControllerInterface.m
// Used under MIT license from http://inquisitivecocoa.com/2009/04/05/key-code-translator/
static wchar_t KeyCodeToChar(CGKeyCode keyCode, unsigned int modifierFlags)
{
	TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource();
	CFDataRef uchr = (CFDataRef)TISGetInputSourceProperty(currentKeyboard, kTISPropertyUnicodeKeyLayoutData);
	const UCKeyboardLayout *keyboardLayout = uchr ? (const UCKeyboardLayout*)CFDataGetBytePtr(uchr) : NULL;
	
	if( keyboardLayout )
	{
		UInt32 deadKeyState = 0;
		UniCharCount maxStringLength = 255;
		UniCharCount actualStringLength = 0;
		UniChar unicodeString[maxStringLength];
		
		OSStatus status = UCKeyTranslate(keyboardLayout,
						 keyCode, kUCKeyActionDown, modifierFlags,
						 LMGetKbdType(), 0,
						 &deadKeyState,
						 maxStringLength,
						 &actualStringLength, unicodeString);
		
		if( status != noErr )
		{
			fprintf(stderr, "There was an %s error translating from the '%d' key code to a human readable string: %s\n",
				GetMacOSStatusErrorString(status), (int)status, GetMacOSStatusCommentString(status));
		}
		else if( actualStringLength == 0 )
		{
			fprintf(stderr, "Couldn't find a translation for the '%d' key code\n", keyCode);
		}
		else
		{
			return unicodeString[0];
		}
	}
	else
	{
		fprintf(stderr, "Couldn't find a translation for the '%d' key code\n", keyCode);
	}
	return 0;
}
void HelperMacX::initUnicodeToKeycodeWithModsMap(){
	unicodeToKeycodeWithModsMap.clear();
	TISInputSourceRef inputSourceRef = TISCopyCurrentKeyboardInputSource();
	if (NULL == inputSourceRef) {
		qWarning("HelperMacX::initUnicodeToKeycodeWithModsMap: inputSourceRef is NULL");
		return;
	}
	CFDataRef unicodeKeyLayoutDataRef = (CFDataRef)TISGetInputSourceProperty(inputSourceRef,
		kTISPropertyUnicodeKeyLayoutData);
	if (NULL == unicodeKeyLayoutDataRef) {
		qWarning("HelperMacX::initUnicodeToKeycodeWithModsMap: unicodeKeyLayoutDataRef is NULL");
		return;
	}
	UCKeyboardLayout *unicodeKeyLayoutDataPtr = (UCKeyboardLayout*)CFDataGetBytePtr(unicodeKeyLayoutDataRef);

	UInt32 deadKeyState;
	UniChar unicodeString[8];
	UniCharCount len;
	for (int m = 0; m < 16; m++) {
		uint mods =  orderedModifiers[m];
		for (uint keycode = 0; keycode < 0x80; keycode++) {
			deadKeyState = 0;
			len = 0;
			OSStatus status = UCKeyTranslate(unicodeKeyLayoutDataPtr, keycode, kUCKeyActionDown,
											 mods, LMGetKbdType(), kUCKeyTranslateNoDeadKeysMask,
											 &deadKeyState, sizeof(unicodeString), &len, unicodeString);
			if (noErr != status) {
				qWarning("HelperMacX::initUnicodeToKeycodeWithModsMap: UCKeyTranslate error: %d keycode 0x%02X modifiers 0x%02X",
						 (int)status, keycode, mods);
				continue;
			}
			// store if only one char and not already in store
			if ((1 != len) || (0 < unicodeToKeycodeWithModsMap.count(unicodeString[0]))) continue;
			unicodeToKeycodeWithModsMap[unicodeString[0]] = (KeycodeWithMods){ keycode, mods };
		}
	}
}
static bool translateKeyEventInternal(EventHandlerCallRef er, EventRef keyEvent, int *qtKey,
                                      QChar *outChar, Qt::KeyboardModifiers *outModifiers, bool *outHandled)
{
#if !defined(QT_MAC_USE_COCOA) || defined(Q_OS_MAC64)
    Q_UNUSED(er);
    Q_UNUSED(outHandled);
#endif
    const UInt32 ekind = GetEventKind(keyEvent);
    {
        UInt32 mac_modifiers = 0;
        GetEventParameter(keyEvent, kEventParamKeyModifiers, typeUInt32, 0,
                          sizeof(mac_modifiers), 0, &mac_modifiers);
#ifdef DEBUG_KEY_BINDINGS_MODIFIERS
        qDebug("************ Mapping modifiers and key ***********");
#endif
        *outModifiers = qt_mac_get_modifiers(mac_modifiers);
#ifdef DEBUG_KEY_BINDINGS_MODIFIERS
        qDebug("------------ Mapping modifiers and key -----------");
#endif
    }

    //get keycode
    UInt32 keyCode = 0;
    GetEventParameter(keyEvent, kEventParamKeyCode, typeUInt32, 0, sizeof(keyCode), 0, &keyCode);

    //get mac mapping
    static UInt32 tmp_unused_state = 0L;
    const UCKeyboardLayout *uchrData = 0;
#if defined(Q_OS_MAC32)
    KeyboardLayoutRef keyLayoutRef = 0;
    KLGetCurrentKeyboardLayout(&keyLayoutRef);
    OSStatus err;
    if (keyLayoutRef != 0) {
        err = KLGetKeyboardLayoutProperty(keyLayoutRef, kKLuchrData,
                                  (reinterpret_cast<const void **>(&uchrData)));
        if (err != noErr) {
            qWarning("Qt::internal::unable to get keyboardlayout %ld %s:%d",
                     long(err), __FILE__, __LINE__);
        }
    }
#else
    QCFType<TISInputSourceRef> inputSource = TISCopyCurrentKeyboardInputSource();
    Q_ASSERT(inputSource != 0);
    CFDataRef data = static_cast<CFDataRef>(TISGetInputSourceProperty(inputSource,
                                                                 kTISPropertyUnicodeKeyLayoutData));
    uchrData = data ? reinterpret_cast<const UCKeyboardLayout *>(CFDataGetBytePtr(data)) : 0;
#endif
    *qtKey = Qt::Key_unknown;
    if (uchrData) {
        // The easy stuff; use the unicode stuff!
        UniChar string[4];
        UniCharCount actualLength;
        UInt32 currentModifiers = GetCurrentEventKeyModifiers();
        UInt32 currentModifiersWOAltOrControl = currentModifiers & ~(controlKey | optionKey);
        int keyAction;
        switch (ekind) {
        default:
        case kEventRawKeyDown:
            keyAction = kUCKeyActionDown;
            break;
        case kEventRawKeyUp:
            keyAction = kUCKeyActionUp;
            break;
        case kEventRawKeyRepeat:
            keyAction = kUCKeyActionAutoKey;
            break;
        }
        OSStatus err = UCKeyTranslate(uchrData, keyCode, keyAction,
                                  ((currentModifiersWOAltOrControl >> 8) & 0xff), LMGetKbdType(),
                                  kUCKeyTranslateNoDeadKeysMask, &tmp_unused_state, 4, &actualLength,
                                  string);
        if (err == noErr) {
            *outChar = QChar(string[0]);
            *qtKey = qt_mac_get_key(*outModifiers, *outChar, keyCode);
            if (currentModifiersWOAltOrControl != currentModifiers) {
                // Now get the real char.
                err = UCKeyTranslate(uchrData, keyCode, keyAction,
                                     ((currentModifiers >> 8) & 0xff), LMGetKbdType(),
                                      kUCKeyTranslateNoDeadKeysMask, &tmp_unused_state, 4, &actualLength,
                                      string);
                if (err == noErr)
                    *outChar = QChar(string[0]);
            }
        } else {
Esempio n. 11
0
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;
		}
	}
Esempio n. 12
0
// This method must be executed from the main runloop to avoid the seemingly random
// Exception detected while handling key input.  TSMProcessRawKeyCode failed (-192) errors.
// CFEqual(CFRunLoopGetCurrent(), CFRunLoopGetMain())
void keycode_to_string(CGEventRef event_ref, UniCharCount size, UniCharCount *length, UniChar *buffer) {
	#if defined(USE_CARBON_LEGACY) || defined(USE_COREFOUNDATION)
	#if defined(USE_CARBON_LEGACY)
	KeyboardLayoutRef curr_keyboard_layout;
	void *inputData = NULL;
	if (KLGetCurrentKeyboardLayout(&curr_keyboard_layout) == noErr) {
		if (KLGetKeyboardLayoutProperty(curr_keyboard_layout, kKLuchrData, (const void **) &inputData) != noErr) {
			inputData = NULL;
		}
	}
	#elif defined(USE_COREFOUNDATION)
	TISInputSourceRef curr_keyboard_layout = TISCopyCurrentKeyboardLayoutInputSource();
	CFDataRef inputData = NULL;
	if (curr_keyboard_layout != NULL && CFGetTypeID(curr_keyboard_layout) == TISInputSourceGetTypeID()) {
		CFDataRef data = (CFDataRef) TISGetInputSourceProperty(curr_keyboard_layout, kTISPropertyUnicodeKeyLayoutData);
		if (data != NULL && CFGetTypeID(data) == CFDataGetTypeID() && CFDataGetLength(data) > 0) {
			inputData = (CFDataRef) data;
		}
	}

	// Check if the keyboard layout has changed to see if the dead key state needs to be discarded.
	if (prev_keyboard_layout != NULL && curr_keyboard_layout != NULL && CFEqual(curr_keyboard_layout, prev_keyboard_layout) == false) {
		curr_deadkey_state = 0;
	}

	// Release the previous keyboard layout.
	if (prev_keyboard_layout != NULL) {
		CFRelease(prev_keyboard_layout);
	}

	// Set the previous keyboard layout to the current layout.
	if (curr_keyboard_layout != NULL) {
		prev_keyboard_layout = curr_keyboard_layout;
	}
	#endif

	if (inputData != NULL) {
		#ifdef USE_CARBON_LEGACY
		const UCKeyboardLayout *keyboard_layout = (const UCKeyboardLayout *) inputData;
		#else
		const UCKeyboardLayout *keyboard_layout = (const UCKeyboardLayout*) CFDataGetBytePtr(inputData);
		#endif

		if (keyboard_layout != NULL) {
			//Extract keycode and modifier information.
			CGKeyCode keycode = CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode);
			CGEventFlags modifiers = CGEventGetFlags(event);

			// Disable all command modifiers for translation.  This is required
			// so UCKeyTranslate will provide a keysym for the separate event.
			static const CGEventFlags cmd_modifiers = kCGEventFlagMaskCommand |
					kCGEventFlagMaskControl | kCGEventFlagMaskAlternate;
			modifiers &= ~cmd_modifiers;

			// I don't know why but UCKeyTranslate does not process the
			// kCGEventFlagMaskAlphaShift (A.K.A. Caps Lock Mask) correctly.
			// We need to basically turn off the mask and process the capital
			// letters after UCKeyTranslate().  Think Different, not because it
			// makes sense but because you want to be a hipster.
			bool is_caps_lock = modifiers & kCGEventFlagMaskAlphaShift;
			modifiers &= ~kCGEventFlagMaskAlphaShift;


			OSStatus status = noErr;
			if (curr_deadkey_state == 0) {
				// No previous deadkey, attempt a lookup.
				status = UCKeyTranslate(
									keyboard_layout,
									keycode,
									kUCKeyActionDown,
									(modifiers >> 16) & 0xFF, //(modifiers >> 16) & 0xFF, || (modifiers >> 8) & 0xFF,
									LMGetKbdType(),
									kNilOptions, //kNilOptions, //kUCKeyTranslateNoDeadKeysMask
									&curr_deadkey_state,
									size,
									length,
									buffer);
			}
			else {
Esempio n. 13
0
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(&currentKeyboardLayout);
#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;
}
Esempio n. 14
0
OP_STATUS UKeyTranslate::GetUnicharFromVirtualKey(UInt32 virtualKeyCode, uni_char &outUniChar, UInt8 modifierKeyState)
{
#ifdef SIXTY_FOUR_BIT
	UInt32 deadKeyState = 0;
	OP_STATUS result = OpStatus::ERR;
	TISInputSourceRef kbInputSourceRef = TISCopyCurrentKeyboardLayoutInputSource();
	CFDataRef uchrDataRef = (CFDataRef)TISGetInputSourceProperty(kbInputSourceRef, kTISPropertyUnicodeKeyLayoutData);
	Boolean existsUchr = ((uchrDataRef != NULL) && (CFDataGetBytePtr(uchrDataRef) != NULL) && (CFDataGetLength(uchrDataRef) != 0));
	if (existsUchr)
	{
		UniCharCount actualLength = 0;
		UniChar outChar[2] = {0,0};

		OSStatus status = UCKeyTranslate((const UCKeyboardLayout *)CFDataGetBytePtr(uchrDataRef),
										 virtualKeyCode, kUCKeyActionDown,
										 modifierKeyState, LMGetKbdType(), kNilOptions,
										 &deadKeyState, 2, &actualLength, outChar);
		if (status == noErr && actualLength && outChar[0] != kFunctionKeyCharCode)
		{
			outUniChar = outChar[0];
			result = OpStatus::OK;
		}
	}
	CFRelease(kbInputSourceRef);

	return result;
#else	// !SIXTY_FOUR_BIT
	static KeyboardLayoutRef lastKbdLayout = 0;
	static const UCKeyboardLayout* ucharData = NULL;
	static const void* charData = NULL;
	KeyboardLayoutRef currentKbdLayout = 0;

	if (noErr != KLGetCurrentKeyboardLayout(&currentKbdLayout) || !currentKbdLayout)
	{
		return OpStatus::ERR;
	}

	short	keyCode;
	OSStatus error = noErr;
	UInt32 deadKeyState = 0;
	OP_STATUS result = OpStatus::ERR;

	keyCode = virtualKeyCode;

	if (!ucharData || (currentKbdLayout != lastKbdLayout))
	{
		// Don't fetch this unless we have to: Because of the KeyScript issue handled below this may in some cases return 0
		// KeyScript is an EXPENSIVE call, so by caching ucharData as long as possible we minimise the number of times
		// we need to call it.
		error = KLGetKeyboardLayoutProperty(currentKbdLayout, kKLuchrData, (const void**)&ucharData);
	}
	if (!ucharData)
	{
		static Boolean try_again = true;
		if (try_again && (smRoman == GetScriptManagerVariable(smKeyScript)))
		{
			// This is required for roman scripts in order to get something from KLGetCurrentKeyboardLayout
			KeyScript(smRoman | smKeyForceKeyScriptMask);
			error = KLGetKeyboardLayoutProperty(currentKbdLayout, kKLuchrData, (const void**)&ucharData);
			if (error || !ucharData)
				try_again = false;
		}
	}

	if ((error == noErr) && (ucharData != 0))
	{
		UniCharCount actualLength = 0;
		UniChar outChar[2] = {0,0};
		charData = NULL;
		error = UCKeyTranslate(ucharData, (unsigned short)keyCode,
									kUCKeyActionDown, modifierKeyState, LMGetKbdType(), 0,
									&deadKeyState, 2, &actualLength, outChar);
		if (error == noErr && actualLength && outChar[0] != kFunctionKeyCharCode)
		{
			outUniChar = outChar[0];
			result = OpStatus::OK;
#ifdef DEBUG_UNI_KEYSTROKES
//			if (outUniChar & 0xff00)
//				fprintf(stderr, "UKC:%x\n", outChar[0]);
#endif
		}
#ifdef DEBUG_UNI_KEYSTROKES
		else
		{
			fprintf(stderr, "UKCe:%li-%x-%lu-%x\n", error, outChar[0], virtualKeyCode, modifierKeyState);
		}
		if (actualLength != 1)
			fprintf(stderr, "UKCl:%lu-%x-%x-%lu-%x\n", actualLength, outChar[0], outChar[1], virtualKeyCode, modifierKeyState);
#endif
	}
	else
	{
#ifdef DEBUG_UNI_KEYSTROKES
		fprintf(stderr, "KLP:%li\n", error);
#endif
		error = noErr;
		if (!charData || (currentKbdLayout != lastKbdLayout))
		{
			error = KLGetKeyboardLayoutProperty(currentKbdLayout, kKLKCHRData, &charData);
		}
		if ((error == noErr) && (charData != 0))
		{
			unsigned long charcs = KeyTranslate(charData, (keyCode & 0xFF) | (modifierKeyState << 8), &deadKeyState);
			if (charcs & 0xFF)
			{
				char src = charcs & 0x00FF;
				gTextConverter->ConvertBufferFromMac(&src, 1, &outUniChar, 1);
				result = OpStatus::OK;
			}
#ifdef DEBUG_UNI_KEYSTROKES
			else
			{
				fprintf(stderr, "KTe\n", outUniChar);
			}
			if (charcs & 0xFF0000)
			{
				fprintf(stderr, "KTe:%x-%lu-%x\n", charcs, virtualKeyCode, modifierKeyState);
			}
#endif
		}
		else
		{
#ifdef DEBUG_UNI_KEYSTROKES
			fprintf(stderr, "KLPe:%li\n", error);
#endif
		}
	}
	lastKbdLayout = currentKbdLayout;
	return result;
#endif	// SIXTY_FOUR_BIT
}
static void PsychHIDKbQueueCallbackFunction(void *target, IOReturn result, void *sender)
{
    // This routine is executed each time the queue transitions from empty to non-empty
    // The CFRunLoop of the thread in KbQueueWorkerThreadMain() is the one that executes here:
    IOHIDQueueRef queue = (IOHIDQueueRef) sender;
    IOHIDValueRef valueRef = NULL;
    int deviceIndex = (int) target;
    double timestamp;
    int eventValue;
    long keysUsage = -1;
    PsychHIDEventRecord evt;
    
    result=kIOReturnError;
    if (!queue) return; // Nothing we can do because we can't access queue, (shouldn't happen)
    
    while (1) {
        // This function only gets called when queue transitions from empty to non-empty
        // Therefore, we must process all available events in this while loop before
        // it will be possible for this function to be notified again.
        if (valueRef) {
            CFRelease(valueRef);
            valueRef = NULL;
        }
        
        // Dequeue next event from queue in a polling non-blocking fashion:
        valueRef = IOHIDQueueCopyNextValueWithTimeout(queue, 0.0);
        
        // Done? Exit, if so:
        if (!valueRef) break;
        
        // Get event value, e.g., the key state of a key or button 1 = pressed, 0 = released:
        eventValue = IOHIDValueGetIntegerValue(valueRef);
        
        // Get usage value, ie., the identity of the key:
        IOHIDElementRef element = IOHIDValueGetElement(valueRef);
        keysUsage = IOHIDElementGetUsage(element);
        
        // Get double GetSecs timestamp, computed from returned uint64 nanoseconds timestamp:
        timestamp = convertTime(IOHIDValueGetTimeStamp(valueRef));
        
        // Don't bother with keysUsage of 0 (meaningless) or 1 (ErrorRollOver) for keyboards:
        if ((queueIsAKeyboard[deviceIndex]) && (keysUsage <= 1)) continue;
        
        // Clear ringbuffer event:
        memset(&evt, 0 , sizeof(evt));
        
        // Cooked key code defaults to "unhandled", and stays that way for anything but keyboards:
        evt.cookedEventCode = -1;
        
        // For real keyboards we can compute cooked key codes: Requires OSX 10.5 or later.
        if (queueIsAKeyboard[deviceIndex]) {
            // Keyboard(ish) device. We can handle this under some conditions.
            // Init to a default of handled, but unmappable/ignored keycode:
            evt.cookedEventCode = 0;
            
            // Keypress event code available in mapping table?
            if (keysUsage < kHID2VKCSize) {
                // Yes: We try to map this to a character code:
                
                // Step 1: Map HID usage value to virtual keycode via LUT:
                uint16_t vcKey = kHID2VKC[keysUsage];
                
                // Keep track of SHIFT keys as modifier keys: Bits 0 == Command, 1 == Shift, 2 == CapsLock, 3 == Alt/Option, 4 == CTRL
                if ((vcKey == kVKC_Shift || vcKey == kVKC_rShift) && (eventValue != 0)) modifierKeyState[deviceIndex] |=  (1 << 1);
                if ((vcKey == kVKC_Shift || vcKey == kVKC_rShift) && (eventValue == 0)) modifierKeyState[deviceIndex] &= ~(1 << 1);
                
                // Keep track of ALT keys as modifier keys:
                if ((vcKey == kVKC_Option || vcKey == kVKC_rOption) && (eventValue != 0)) modifierKeyState[deviceIndex] |=  (1 << 3);
                if ((vcKey == kVKC_Option || vcKey == kVKC_rOption) && (eventValue == 0)) modifierKeyState[deviceIndex] &= ~(1 << 3);
                
                // Keep track of CTRL keys as modifier keys:
                if ((vcKey == kVKC_Control || vcKey == kVKC_rControl) && (eventValue != 0)) modifierKeyState[deviceIndex] |=  (1 << 4);
                if ((vcKey == kVKC_Control || vcKey == kVKC_rControl) && (eventValue == 0)) modifierKeyState[deviceIndex] &= ~(1 << 4);
                
                // Was this a CTRL + C interrupt request?
                if ((eventValue != 0) && (vcKey == 0x08) && (modifierKeyState[deviceIndex] & (1 << 4))) {
                    // Yes: Tell the console input helper about it, so it can send interrupt
                    // signals to the runtime and reenable keyboard input if appropriate:
                    // Note: Not sure if the mutex exclusion is needed here, but better safe than sorry.
                    PsychLockMutex(&KbQueueMutex);
                    ConsoleInputHelper(-1);
                    PsychUnlockMutex(&KbQueueMutex);
                }
                
                // Key press?
                if (eventValue != 0) {
                    // Step 2: Translate virtual key code into unicode char:
                    // Ok, this is the usual horrifying complexity of Apple's system. We use code
                    // snippets found on StackOverflow, modified to suit our needs, e.g., we track
                    // modifier keys manually, at least left and right ALT and SHIFT keys. We don't
                    // care about other modifiers.
                    TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource();
                    CFDataRef uchr = (CFDataRef) ((currentKeyboard) ? TISGetInputSourceProperty(currentKeyboard, kTISPropertyUnicodeKeyLayoutData) : NULL);
                    const UCKeyboardLayout *keyboardLayout = (const UCKeyboardLayout*) ((uchr) ? CFDataGetBytePtr(uchr) : NULL);
                    
                    if (keyboardLayout) {
                        UInt32 deadKeyState = 0;
                        UniCharCount maxStringLength = 255;
                        UniCharCount actualStringLength = 0;
                        UniChar unicodeString[maxStringLength];
                        
                        OSStatus status = UCKeyTranslate(keyboardLayout,
                                                         vcKey, kUCKeyActionDown, modifierKeyState[deviceIndex],
                                                         LMGetKbdType(), 0,
                                                         &deadKeyState,
                                                         maxStringLength,
                                                         &actualStringLength, unicodeString);
                        
                        if ((actualStringLength == 0) && deadKeyState) {
                            status = UCKeyTranslate(keyboardLayout,
                                                    kVK_Space, kUCKeyActionDown, 0,
                                                    LMGetKbdType(), 0,
                                                    &deadKeyState,
                                                    maxStringLength,
                                                    &actualStringLength, unicodeString);
                        }
                        
                        if((actualStringLength > 0) && (status == noErr)) {
                            // Assign final cooked / mapped keycode:
                            evt.cookedEventCode = (int) unicodeString[0];
                            
                            // Send same keystroke character to console input helper.
                            // In kbqueue-based ListenChar(1) mode, the helper will
                            // inject/forward the character into the runtime:
                            // Note: ConsoleInputHelper() should be safe to call without
                            // mutex protection for >= 0 event codes.
                            ConsoleInputHelper(evt.cookedEventCode);
                        }
                    }
                }
            }
        }
        
        PsychLockMutex(&KbQueueMutex);

        // Update records of first and latest key presses and releases
        if (eventValue != 0) {
            if (psychHIDKbQueueFirstPress[deviceIndex]) {
                // First key press timestamp:
                if (psychHIDKbQueueFirstPress[deviceIndex][keysUsage-1] == 0) {
                    psychHIDKbQueueFirstPress[deviceIndex][keysUsage-1] = timestamp;
                }
            }

            if (psychHIDKbQueueLastPress[deviceIndex]) {
                // Last key press timestamp:
                psychHIDKbQueueLastPress[deviceIndex][keysUsage-1] = timestamp;
            }
            evt.status |= (1 << 0);
        }
        else {
            if (psychHIDKbQueueFirstRelease[deviceIndex]) {
                // First key release timestamp:
                if (psychHIDKbQueueFirstRelease[deviceIndex][keysUsage-1] == 0) psychHIDKbQueueFirstRelease[deviceIndex][keysUsage-1] = timestamp;
            }

            if (psychHIDKbQueueLastRelease[deviceIndex]) {
                // Last key release timestamp:
                psychHIDKbQueueLastRelease[deviceIndex][keysUsage-1] = timestamp;
            }
            evt.status &= ~(1 << 0);
        }

        // Update event buffer:
        evt.timestamp = timestamp;
        evt.rawEventCode = keysUsage;
        PsychHIDAddEventToEventBuffer(deviceIndex, &evt);

        // Tell waiting userspace (under KbQueueMutxex protection for better scheduling) something interesting has changed:
        PsychSignalCondition(&KbQueueCondition);

        PsychUnlockMutex(&KbQueueMutex);

        // Next while loop iteration to dequeue potentially more events:
    }
    
    // Done for this queue transition. Return to runloop.
}
Esempio n. 16
0
void updateScancodes()
{
#ifdef QT_MAC_USE_COCOA
    TISInputSourceRef layout = TISCopyCurrentKeyboardLayoutInputSource();
    if (!layout) {
        qWarning() << "Error retrieving current layout";
        return;
    }
    if (layout == lastLayout) {
        CFRelease(layout);
    } else {
        // keyboard layout changed
#ifndef NDEBUG
        const void *name = TISGetInputSourceProperty(layout, kTISPropertyLocalizedName);
        qDebug() << "Layout changed to: " << CFStringGetCStringPtr((CFStringRef)name, 0);
#endif
        lastLayout = layout;
        scancodes.clear();

        CFDataRef data = static_cast<CFDataRef>(TISGetInputSourceProperty(layout,
                                                kTISPropertyUnicodeKeyLayoutData));
        const UCKeyboardLayout *ucData = data ? reinterpret_cast<const UCKeyboardLayout *>(CFDataGetBytePtr(data)) : 0;

        if (!ucData) {
            qWarning() << "Error retrieving current layout character data";
            return;
        }

        for (int i = 0; i < 128; ++i) {
            UInt32 tmpState = 0;
            UniChar str[4];
            UniCharCount actualLength = 0;
            OSStatus err = UCKeyTranslate(ucData, i, kUCKeyActionDown, 0, LMGetKbdType(),
                                          kUCKeyTranslateNoDeadKeysMask, &tmpState, 4, &actualLength, str);
            if (err != noErr) {
                qWarning() << "Error translating unicode key" << err;
            } else {
                if (str[0] && str[0] != kFunctionKeyCharCode) {
                    scancodes.insert(str[0], i);
                }
            }
        }
    }
#else
    KeyboardLayoutRef layout;
    if (KLGetCurrentKeyboardLayout(&layout) != noErr) {
        qWarning() << "Error retrieving current layout";
    }
    if (layout != lastLayout) {
#ifndef NDEBUG
        void *name;
        KLGetKeyboardLayoutProperty(layout, kKLName, const_cast<const void **>(&name));
        qDebug() << "Layout changed to: " << CFStringGetCStringPtr((CFStringRef) name, 0);
#endif
        lastLayout = layout;
        scancodes.clear();
        void *kchr;
        if (KLGetKeyboardLayoutProperty(layout, kKLKCHRData, const_cast<const void **>(&kchr)) != noErr) {
            qWarning() << "Couldn't load active keyboard layout";
        } else {
            for (int i = 0; i < 128; i++) {
                UInt32 tmpState = 0;
                UInt32 chr = KeyTranslate(kchr, i, &tmpState);
                if (chr && chr != kFunctionKeyCharCode) {
                    scancodes.insert(chr, i);
                }
            }
        }
    }
#endif
}