如何ASCII字符转换为CGKey code? [英] How to convert ASCII character to CGKeyCode?

查看:403
本文介绍了如何ASCII字符转换为CGKey code?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要一个函数,给定一个字符,返回与该角色对当前的键盘布局的位置 CGKey code 相关。例如,考虑到B,它应该返回 kVK_ANSI_B 如果要是使用德沃夏克使用美国QWERTY或45。在Win32 API所具有的功能 VkKeyScan() 用于此目的; X11所具有的功能<一个href=\"http://tronche.com/gui/x/xlib/utilities/keyboard/XStringToKeysym.html\"><$c$c>XStringToKeySym().是否有对CG API中这样的功能?

I need a function that, given a character, returns the CGKeyCode associated with the position of that character on the current keyboard layout. E.g., given "b", it should return kVK_ANSI_B if using U.S. QWERTY, or 45 if using Dvorak. The Win32 API has the function VkKeyScan() for this purpose; X11 has the function XStringToKeySym(). Is there such a function in the CG API?

我需要这一点是为了传递参数给<一个href=\"http://developer.apple.com/mac/library/documentation/Carbon/Reference/QuartzEventServicesRef/Reference/reference.html#//apple%5Fref/c/func/CGEventCreateKeyboardEvent\"><$c$c>CGEventCreateKeyboardEvent().我已经尝试使用<一个href=\"http://developer.apple.com/mac/library/documentation/Carbon/Reference/QuartzEventServicesRef/Reference/reference.html#//apple%5Fref/c/func/CGEventKeyboardSetUni$c$cString\"><$c$c>CGEventKeyboardSetUni$c$cString()相反,但是,显然不支持修饰符标志(我需要)。

I need this in order to pass a parameter to CGEventCreateKeyboardEvent(). I've tried using CGEventKeyboardSetUnicodeString() instead, but that apparently does not support modifier flags (which I need).

我已经广泛地搜索了这一点,但无法找到一个像样的答案。目前我使用下面的code(在网上找到),其工作方式,但不完全是优雅的(而难以破译如何简化),我会preFER不要在生产code使用它:

I have searched extensively for this but cannot find a decent answer. Currently I am using the following code (found online), which works, but is not exactly elegant (and rather difficult to decipher how to simplify) and I would prefer not to use it in production code:

#include <stdint.h>
#include <stdio.h>
#include <ApplicationServices/ApplicationServices.h>

CGKeyCode keyCodeForCharWithLayout(const char c,
                                   const UCKeyboardLayout *uchrHeader);

CGKeyCode keyCodeForChar(const char c)
{
    CFDataRef currentLayoutData;
    TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource();

    if (currentKeyboard == NULL) {
    	fputs("Could not find keyboard layout\n", stderr);
    	return UINT16_MAX;
    }

    currentLayoutData = TISGetInputSourceProperty(currentKeyboard,
                                                kTISPropertyUnicodeKeyLayoutData);
    CFRelease(currentKeyboard);
    if (currentLayoutData == NULL) {
    	fputs("Could not find layout data\n", stderr);
    	return UINT16_MAX;
    }

    return keyCodeForCharWithLayout(c,
           (const UCKeyboardLayout *)CFDataGetBytePtr(currentLayoutData));
}

/* Beware! Messy, incomprehensible code ahead!
 * TODO: XXX: FIXME! Please! */
CGKeyCode keyCodeForCharWithLayout(const char c,
                                   const UCKeyboardLayout *uchrHeader)
{
    uint8_t *uchrData = (uint8_t *)uchrHeader;
    UCKeyboardTypeHeader *uchrKeyboardList = uchrHeader->keyboardTypeList;

    /* Loop through the keyboard type list. */
    ItemCount i, j;
    for (i = 0; i < uchrHeader->keyboardTypeCount; ++i) {
    	/* Get a pointer to the keyToCharTable structure. */
    	UCKeyToCharTableIndex *uchrKeyIX = (UCKeyToCharTableIndex *)
    	(uchrData + (uchrKeyboardList[i].keyToCharTableIndexOffset));

    	/* Not sure what this is for but it appears to be a safeguard... */
    	UCKeyStateRecordsIndex *stateRecordsIndex;
    	if (uchrKeyboardList[i].keyStateRecordsIndexOffset != 0) {
    		stateRecordsIndex = (UCKeyStateRecordsIndex *)
    			(uchrData + (uchrKeyboardList[i].keyStateRecordsIndexOffset));

    		if ((stateRecordsIndex->keyStateRecordsIndexFormat) !=
    		    kUCKeyStateRecordsIndexFormat) {
    			stateRecordsIndex = NULL;
    		}
    	} else {
    		stateRecordsIndex = NULL;
    	}

    	/* Make sure structure is a table that can be searched. */
    	if ((uchrKeyIX->keyToCharTableIndexFormat) != kUCKeyToCharTableIndexFormat) {
    		continue;
    	}

    	/* Check the table of each keyboard for character */
    	for (j = 0; j < uchrKeyIX->keyToCharTableCount; ++j) {
    		UCKeyOutput *keyToCharData =
    			(UCKeyOutput *)(uchrData + (uchrKeyIX->keyToCharTableOffsets[j]));

    		/* Check THIS table of the keyboard for the character. */
    		UInt16 k;
    		for (k = 0; k < uchrKeyIX->keyToCharTableSize; ++k) {
    			/* Here's the strange safeguard again... */
    			if ((keyToCharData[k] & kUCKeyOutputTestForIndexMask) ==
    			    kUCKeyOutputStateIndexMask) {
    				long keyIndex = (keyToCharData[k] & kUCKeyOutputGetIndexMask);
    				if (stateRecordsIndex != NULL &&
    					keyIndex <= (stateRecordsIndex->keyStateRecordCount)) {
    					UCKeyStateRecord *stateRecord = (UCKeyStateRecord *)
    					                                (uchrData +
    					(stateRecordsIndex->keyStateRecordOffsets[keyIndex]));

    					if ((stateRecord->stateZeroCharData) == c) {
    						return (CGKeyCode)k;
    					}
    				} else if (keyToCharData[k] == c) {
    					return (CGKeyCode)k;
    				}
    			} else if (((keyToCharData[k] & kUCKeyOutputTestForIndexMask)
    						!= kUCKeyOutputSequenceIndexMask) &&
    					   keyToCharData[k] != 0xFFFE &&
    			           keyToCharData[k] != 0xFFFF &&
    					   keyToCharData[k] == c) {
    				return (CGKeyCode)k;
    			}
    		}
    	}
    }

    return UINT16_MAX;
}

是否有一个。)(preferably)我俯瞰一个标准的功能,或b。)(几乎可以肯定)更优雅的方式写我自己?

Is there a.) (preferably) a standard function I am overlooking, or b.) (almost certainly) a more elegant way write my own?

推荐答案

这是我最终使用。干净多了。

This is what I ended up using. Much cleaner.

#include <CoreFoundation/CoreFoundation.h>
#include <Carbon/Carbon.h> /* For kVK_ constants, and TIS functions. */

/* 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 =
        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);
}

/* Returns key code for given character via the above function, or UINT16_MAX
 * on error. */
CGKeyCode keyCodeForChar(const char c)
{
    static CFMutableDictionaryRef charToCodeDict = NULL;
    CGKeyCode code;
    UniChar character = c;
    CFStringRef charStr = NULL;

    /* Generate table of keycodes and characters. */
    if (charToCodeDict == NULL) {
        size_t i;
        charToCodeDict = CFDictionaryCreateMutable(kCFAllocatorDefault,
                                                   128,
                                                   &kCFCopyStringDictionaryKeyCallBacks,
                                                   NULL);
        if (charToCodeDict == NULL) return UINT16_MAX;

        /* Loop through every keycode (0 - 127) to find its current mapping. */
        for (i = 0; i < 128; ++i) {
            CFStringRef string = createStringForKey((CGKeyCode)i);
            if (string != NULL) {
                CFDictionaryAddValue(charToCodeDict, string, (const void *)i);
                CFRelease(string);
            }
        }
    }

    charStr = CFStringCreateWithCharacters(kCFAllocatorDefault, &character, 1);

    /* Our values may be NULL (0), so we need to use this function. */
    if (!CFDictionaryGetValueIfPresent(charToCodeDict, charStr,
                                       (const void **)&code)) {
        code = UINT16_MAX;
    }

    CFRelease(charStr);
    return code;
}

这篇关于如何ASCII字符转换为CGKey code?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆