Ich brauche eine Funktion, die bei einem gegebenen Zeichen die zurückgibt CGKeyCode der Position dieses Zeichens auf dem aktuellen Tastaturlayout zugeordnet ist. Wenn zB “b” gegeben ist, sollte es zurückkehren kVK_ANSI_B wenn Sie US-QWERTZ verwenden, oder kVK_ANSI_N wenn Sie Dvorak verwenden.
Die Win32-API hat die Funktion VkKeyScan() für diesen Zweck; X11 hat die Funktion XStringToKeySym(). Gibt es eine solche Funktion in der CG-API?
Ich habe intensiv danach gesucht, aber keine vernünftige Antwort gefunden. Derzeit verwende ich den folgenden Code (im Netz gefunden), was funktioniert, aber nicht gerade elegant ist (und ziemlich schwer zu entziffern ist, wie man es vereinfacht) und ich würde es vorziehen, es nicht im Produktionscode zu verwenden:
#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;
}
Gibt es a.) (vorzugsweise) eine Standardfunktion, die ich übersehe, oder b.) (mit ziemlicher Sicherheit) eine elegantere Möglichkeit, meine eigene zu schreiben?
@Sneakyness: Ich möchte die Schlüsselkonstanten nicht fest codieren. Sie werden a.) durch Benutzereingaben generiert und b.) können das Ergebnis mehrerer Tastaturlayouts sein.
– Michael
28. Dezember 2009 um 1:01 Uhr
@Michael – Hast du die funktionierende Version des Keyloggers bekommen? Ich suche einen. Ich habe einige Git-Pakete ausprobiert. Funktioniert aber nicht wie erwartet/ erfasst nicht alle Tastenanschläge. Oder haben Sie hierzu Vorschläge? Irgendwelche Open-Source-Pakete? Es wäre sehr hilfreich
– Dany
4. März 2016 um 4:37 Uhr
Michael
Dies ist, was ich am Ende verwendet habe. Viel sauberer.
#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;
}
Für nicht druckbare Schlüssel habe ich die unter (in Carbon) definierten Keycode-Konstanten verwendet. ZB kVK_Delete für die Löschtaste, kVK_F# für Funktionstasten usw.). Dies ist die einzige Methode, die ich finden konnte, die funktionieren würde.
– Michael
20. März 2010 um 18:17 Uhr
Weiß jemand, wie man das mit Kakao statt Kohlenstoff macht?
– Loknar
21. Oktober 2014 um 0:26 Uhr
Die Lösung für den obigen Absturz scheint zu sein, zu ersetzen TISCopyCurrentKeyboardInputSource mit TISCopyCurrentKeyboardLayoutInputSource. Diese Funktion greift auf die aktuelle Tastatur zurück Layoutauch wenn die aktuell ausgewählte Tastatureingabequelle stattdessen eine Eingabemethode oder ein Eingabemodus ist.
– pkamb
18. Juni 2015 um 6:23 Uhr
Ich bin auch neugierig auf eine aktualisierte (möglicherweise Cocoa) Version davon. Außerdem ist diese Version Ursache für Segfaults in meiner Anwendung, selbst mit dem oben genannten Fix, hat jemand einen Fix?
– Theo Winterhalter
6. November 2015 um 23:50 Uhr
Dieser Code ist gefährlich! CGKeyCode code; ist zu klein für den von geschriebenen Wert CFDictionaryGetValueIfPresent. Sie sollten einen Typ mit einer Größe >= sizeof(void*) verwenden. uintptr_t zum Beispiel.
– Benutzer3647854
17. Februar 2017 um 17:46 Uhr
+ (NSString *)keyStringFormKeyCode:(CGKeyCode)keyCode
{
// Proper key detection seems to want a switch statement, unfortunately
switch (keyCode)
{
case 0: return @"a";
case 1: return @"s";
case 2: return @"d";
case 3: return @"f";
case 4: return @"h";
case 5: return @"g";
case 6: return @"z";
case 7: return @"x";
case 8: return @"c";
case 9: return @"v";
// what is 10?
case 11: return @"b";
case 12: return @"q";
case 13: return @"w";
case 14: return @"e";
case 15: return @"r";
case 16: return @"y";
case 17: return @"t";
case 18: return @"1";
case 19: return @"2";
case 20: return @"3";
case 21: return @"4";
case 22: return @"6";
case 23: return @"5";
case 24: return @"=";
case 25: return @"9";
case 26: return @"7";
case 27: return @"-";
case 28: return @"8";
case 29: return @"0";
case 30: return @"]";
case 31: return @"o";
case 32: return @"u";
case 33: return @"[";
case 34: return @"i";
case 35: return @"p";
case 36: return @"RETURN";
case 37: return @"l";
case 38: return @"j";
case 39: return @"'";
case 40: return @"k";
case 41: return @";";
case 42: return @"\\";
case 43: return @",";
case 44: return @"https://stackoverflow.com/";
case 45: return @"n";
case 46: return @"m";
case 47: return @".";
case 48: return @"TAB";
case 49: return @"SPACE";
case 50: return @"`";
case 51: return @"DELETE";
case 52: return @"ENTER";
case 53: return @"ESCAPE";
// some more missing codes abound, reserved I presume, but it would
// have been helpful for Apple to have a document with them all listed
case 65: return @".";
case 67: return @"*";
case 69: return @"+";
case 71: return @"CLEAR";
case 75: return @"https://stackoverflow.com/";
case 76: return @"ENTER"; // numberpad on full kbd
case 78: return @"-";
case 81: return @"=";
case 82: return @"0";
case 83: return @"1";
case 84: return @"2";
case 85: return @"3";
case 86: return @"4";
case 87: return @"5";
case 88: return @"6";
case 89: return @"7";
case 91: return @"8";
case 92: return @"9";
case 96: return @"F5";
case 97: return @"F6";
case 98: return @"F7";
case 99: return @"F3";
case 100: return @"F8";
case 101: return @"F9";
case 103: return @"F11";
case 105: return @"F13";
case 107: return @"F14";
case 109: return @"F10";
case 111: return @"F12";
case 113: return @"F15";
case 114: return @"HELP";
case 115: return @"HOME";
case 116: return @"PGUP";
case 117: return @"DELETE"; // full keyboard right side numberpad
case 118: return @"F4";
case 119: return @"END";
case 120: return @"F2";
case 121: return @"PGDN";
case 122: return @"F1";
case 123: return @"LEFT";
case 124: return @"RIGHT";
case 125: return @"DOWN";
case 126: return @"UP";
default:
return @"Unknown key";
// Unknown key, bail and note that RUI needs improvement
//fprintf(stderr, "%ld\tKey\t%c (DEBUG: %d)\n", currenttime, keyCode;
//exit(EXIT_FAILURE;
}
}
+ (CGKeyCode)keyCodeFormKeyString:(NSString *)keyString
{
if ([keyString isEqualToString:@"a"]) return 0;
if ([keyString isEqualToString:@"s"]) return 1;
if ([keyString isEqualToString:@"d"]) return 2;
if ([keyString isEqualToString:@"f"]) return 3;
if ([keyString isEqualToString:@"h"]) return 4;
if ([keyString isEqualToString:@"g"]) return 5;
if ([keyString isEqualToString:@"z"]) return 6;
if ([keyString isEqualToString:@"x"]) return 7;
if ([keyString isEqualToString:@"c"]) return 8;
if ([keyString isEqualToString:@"v"]) return 9;
// what is 10?
if ([keyString isEqualToString:@"b"]) return 11;
if ([keyString isEqualToString:@"q"]) return 12;
if ([keyString isEqualToString:@"w"]) return 13;
if ([keyString isEqualToString:@"e"]) return 14;
if ([keyString isEqualToString:@"r"]) return 15;
if ([keyString isEqualToString:@"y"]) return 16;
if ([keyString isEqualToString:@"t"]) return 17;
if ([keyString isEqualToString:@"1"]) return 18;
if ([keyString isEqualToString:@"2"]) return 19;
if ([keyString isEqualToString:@"3"]) return 20;
if ([keyString isEqualToString:@"4"]) return 21;
if ([keyString isEqualToString:@"6"]) return 22;
if ([keyString isEqualToString:@"5"]) return 23;
if ([keyString isEqualToString:@"="]) return 24;
if ([keyString isEqualToString:@"9"]) return 25;
if ([keyString isEqualToString:@"7"]) return 26;
if ([keyString isEqualToString:@"-"]) return 27;
if ([keyString isEqualToString:@"8"]) return 28;
if ([keyString isEqualToString:@"0"]) return 29;
if ([keyString isEqualToString:@"]"]) return 30;
if ([keyString isEqualToString:@"o"]) return 31;
if ([keyString isEqualToString:@"u"]) return 32;
if ([keyString isEqualToString:@"["]) return 33;
if ([keyString isEqualToString:@"i"]) return 34;
if ([keyString isEqualToString:@"p"]) return 35;
if ([keyString isEqualToString:@"RETURN"]) return 36;
if ([keyString isEqualToString:@"l"]) return 37;
if ([keyString isEqualToString:@"j"]) return 38;
if ([keyString isEqualToString:@"'"]) return 39;
if ([keyString isEqualToString:@"k"]) return 40;
if ([keyString isEqualToString:@";"]) return 41;
if ([keyString isEqualToString:@"\\"]) return 42;
if ([keyString isEqualToString:@","]) return 43;
if ([keyString isEqualToString:@"https://stackoverflow.com/"]) return 44;
if ([keyString isEqualToString:@"n"]) return 45;
if ([keyString isEqualToString:@"m"]) return 46;
if ([keyString isEqualToString:@"."]) return 47;
if ([keyString isEqualToString:@"TAB"]) return 48;
if ([keyString isEqualToString:@"SPACE"]) return 49;
if ([keyString isEqualToString:@"`"]) return 50;
if ([keyString isEqualToString:@"DELETE"]) return 51;
if ([keyString isEqualToString:@"ENTER"]) return 52;
if ([keyString isEqualToString:@"ESCAPE"]) return 53;
// some more missing codes abound, reserved I presume, but it would
// have been helpful for Apple to have a document with them all listed
if ([keyString isEqualToString:@"."]) return 65;
if ([keyString isEqualToString:@"*"]) return 67;
if ([keyString isEqualToString:@"+"]) return 69;
if ([keyString isEqualToString:@"CLEAR"]) return 71;
if ([keyString isEqualToString:@"https://stackoverflow.com/"]) return 75;
if ([keyString isEqualToString:@"ENTER"]) return 76; // numberpad on full kbd
if ([keyString isEqualToString:@"="]) return 78;
if ([keyString isEqualToString:@"="]) return 81;
if ([keyString isEqualToString:@"0"]) return 82;
if ([keyString isEqualToString:@"1"]) return 83;
if ([keyString isEqualToString:@"2"]) return 84;
if ([keyString isEqualToString:@"3"]) return 85;
if ([keyString isEqualToString:@"4"]) return 86;
if ([keyString isEqualToString:@"5"]) return 87;
if ([keyString isEqualToString:@"6"]) return 88;
if ([keyString isEqualToString:@"7"]) return 89;
if ([keyString isEqualToString:@"8"]) return 91;
if ([keyString isEqualToString:@"9"]) return 92;
if ([keyString isEqualToString:@"F5"]) return 96;
if ([keyString isEqualToString:@"F6"]) return 97;
if ([keyString isEqualToString:@"F7"]) return 98;
if ([keyString isEqualToString:@"F3"]) return 99;
if ([keyString isEqualToString:@"F8"]) return 100;
if ([keyString isEqualToString:@"F9"]) return 101;
if ([keyString isEqualToString:@"F11"]) return 103;
if ([keyString isEqualToString:@"F13"]) return 105;
if ([keyString isEqualToString:@"F14"]) return 107;
if ([keyString isEqualToString:@"F10"]) return 109;
if ([keyString isEqualToString:@"F12"]) return 111;
if ([keyString isEqualToString:@"F15"]) return 113;
if ([keyString isEqualToString:@"HELP"]) return 114;
if ([keyString isEqualToString:@"HOME"]) return 115;
if ([keyString isEqualToString:@"PGUP"]) return 116;
if ([keyString isEqualToString:@"DELETE"]) return 117;
if ([keyString isEqualToString:@"F4"]) return 118;
if ([keyString isEqualToString:@"END"]) return 119;
if ([keyString isEqualToString:@"F2"]) return 120;
if ([keyString isEqualToString:@"PGDN"]) return 121;
if ([keyString isEqualToString:@"F1"]) return 122;
if ([keyString isEqualToString:@"LEFT"]) return 123;
if ([keyString isEqualToString:@"RIGHT"]) return 124;
if ([keyString isEqualToString:@"DOWN"]) return 125;
if ([keyString isEqualToString:@"UP"]) return 126;
return 0;
//fprintf(stderr, "keyString %s Not Found. Aborting...\n", keyString);
//exit(EXIT_FAILURE);
}
Dies würde nur für US-QWERTZ funktionieren … nicht die beste Lösung.
– pkamb
4. Oktober 2013 um 18:31 Uhr
Fall 10 scheint das Dollarzeichen ($) zu sein.
– dalgard
13. Oktober 2019 um 11:16 Uhr
Theo Winterhalter
Für diejenigen wie mich, die nach mehr gesucht haben auf dem neusten Stand Version von dem, was Michael vorgeschlagen hat, hier ist, was ich am Ende selbst gemacht habe (für mich hat es ein Segfault-Problem gelöst, wahrscheinlich weil der Garbage Collector seine Arbeit mit dieser Version erledigt).
Die erste Funktion stammt von Convert Virtual Key Code to Unicode String.
ich benutzte NSNumber um ein Nullable-Objekt zu erhalten, den Wert, der von zurückgegeben wird charToKeyCode(c) kann dann gegen getestet werden nil und dann mit aufgerufen (CGKeyCode)[charToKeyCode(c) intValue].
Kennen Sie eine Lösung ohne Kohlenstoff?
– Jan
13. Juli 2020 um 20:20 Uhr
Ich glaube, das ist ein Speicherverlust – ich denke, das müssen Sie tun CFRelease(currentKeyboard); vor den beiden return-Anweisungen in keyCodeToString().
– s3cur3
22. März 2021 um 14:49 Uhr
Ich weiß, dass diese Frage jetzt Jahre alt ist, aber falls es noch jemanden interessiert, ich habe eine Version davon verspottet, die nicht auf Kohlenstoffroutinen angewiesen ist. Tatsächlich geht es ein bisschen weiter, weil es abbilden wird irgendein Zeichen, das in seine Kombination aus virtuellem Tastencode und Modifikator zurückgetippt werden kann.
- (NSDictionary *)characterToKeyCode:(NSString *)character {
static NSDictionary * keyMapDict;
if (keyMapDict == nil) {
keyMapDict = [self makeKeyMap];
}
/*
The returned dictionary contains entries for the virtual key code and boolen flags
for modifier keys used for the character.
*/
return [keyMapDict objectForKey:character];
}
- (NSDictionary *)makeKeyMap {
CGKeyCode keyCode;
CGEventRef coreEvent;
NSEvent * keyEvent;
NSUInteger modifiers = 0;
NSMutableDictionary * subDict, * keyMapDict;
NSString *character;
BOOL modKeyIsUsed;
static NSDictionary * modFlagDict;
static NSArray * modFlags;
// create dictionary of modifier names and keys. I've used all the modifiers, but I doubt theya re all needed.
if (modFlagDict == nil) {
modFlagDict = @{@"option":@(NSEventModifierFlagOption),
@"shift": @(NSEventModifierFlagShift),
@"function":@(NSEventModifierFlagFunction),
@"control": @(NSEventModifierFlagControl),
@"command":@(NSEventModifierFlagCommand)};
modFlags = [modFlagDict allValues];
}
keyMapDict = [NSMutableDictionary dictionary];
// run through 128 base key codes to see what they produce
for (keyCode = 0; keyCode < 128; ++keyCode) {
// create dummy NSEvent from a CGEvent for a keypress
coreEvent = CGEventCreateKeyboardEvent(NULL, keyCode, true);
keyEvent = [NSEvent eventWithCGEvent:coreEvent];
CFRelease(coreEvent);
if (keyEvent.type == NSEventTypeKeyDown) {
// this do/while loop through every permutation of modifier keys for a given key code
do {
subDict = [NSMutableDictionary dictionary];
// cerate dictionary containing current modifier keys and virtual key code
for (NSString * key in modFlagDict) {
modKeyIsUsed = ([(NSNumber *)[modFlagDict objectForKey:key] unsignedLongValue] & modifiers) ? YES : NO;
[subDict setObject:[NSNumber numberWithBool:modKeyIsUsed]
forKey:key];
}
[subDict setObject:[NSNumber numberWithUnsignedLong:(unsigned long)keyCode]
forKey:@"virtKeyCode"];
// manipulate the NSEvent to get character produce by virtual key code and modifiers
if (modifiers == 0) {
character = [keyEvent characters];
} else {
character = [keyEvent charactersByApplyingModifiers:modifiers];
}
// add sub-dictionary to main dictionary using character as key
if (![keyMapDict objectForKey:character]) {
[keyMapDict setObject:[NSDictionary dictionaryWithDictionary:subDict]
forKey:character];
}
// permutate the modifiers
modifiers = [self permutatateMods:modFlags];
} while (modifiers != 0);
}
}
return [NSDictionary dictionaryWithDictionary:keyMapDict];
}
- (NSUInteger)permutatateMods:(NSArray *) modFlags {
static NSMutableIndexSet * idxSet;
NSArray * modArray;
NSEnumerator * e;
NSNumber * modObj;
NSUInteger modifiers = 0, idx = 0;
if (idxSet == nil) {
idxSet = [NSMutableIndexSet indexSet];
}
/*
Starting at 0, if the index exists, remove it and move up; if the index doesn't exist, add it. Will
cycle through a standard binary progression. Indexes are then applied to the passed array, and the
selected elements are 'OR'ed together
*/
BOOL doneFlag = NO;
while (!doneFlag) {
if ([idxSet containsIndex:idx]) {
[idxSet removeIndex:idx++];
continue;
}
if (idx < [modFlags count]) {
[idxSet addIndex:idx];
} else {
[idxSet removeAllIndexes];
}
doneFlag = YES;
}
modArray = [modFlags objectsAtIndexes:idxSet];
e = [modArray objectEnumerator];
while (modObj = [e nextObject]) {
modifiers |= [modObj unsignedIntegerValue];
}
return modifiers;
}
Zum Beispiel, wenn Sie es wie folgt aufrufen
NSDictionary * d = [self characterToKeyCode:@"π"];
invalid conversion from 'void*' to 'const __CFData*'
Die Dokumentation sagt, dass der Wert für kTISPropertyUnicodeKeyLayoutData ist ein CFDataRef, also ist diese Besetzung richtig. Der Fehler hat nichts mit Qt zu tun; es wird stattdessen durch Ihre Einstellungen (wie paranoid Sie den Compiler konfiguriert haben) oder die Wahl der Sprache (I denken Es ist wahrscheinlicher, dass Sie diesen Fehler in C++ erhalten, aber ich könnte mich irren und kenne keine Einzelheiten).
– Peter Hosey
3. Januar 2013 um 23:22 Uhr
Für die Zwecke dieser Frage scheint es 3 Arten von Schlüsseln zu geben, die a erzeugen CGKeyCode:
einfaches Unicode-Zeichen, z. B. A
eine Zusatztaste, zB Shift
eine spezielle Taste, zB F1.
Ich habe mich an Ted Wrigleys Antwort orientiert, um geeignete Swift-Initialisierer für alle drei Typen zu erstellen. Das Beispiel aus CGEvent(keyboardEventSource:virtualKey:keyDown:) kann jetzt geschrieben werden:
guard let shiftKeyCode = CGKeyCode(modifierFlag: .shift) else { fatalError() }
guard let zKeyCode = CGKeyCode(character: "z") else { fatalError() }
let event1 = CGEvent(keyboardEventSource: nil, virtualKey: shiftKeyCode, keyDown: true)
let event2 = CGEvent(keyboardEventSource: nil, virtualKey: zKeyCode, keyDown: true)
let event3 = CGEvent(keyboardEventSource: nil, virtualKey: zKeyCode, keyDown: false)
let event4 = CGEvent(keyboardEventSource: nil, virtualKey: shiftKeyCode, keyDown: false)
//
// CGKeyCodeInitializers.swift
//
// Created by John Scott on 09/02/2022.
//
import Foundation
import AppKit
extension CGKeyCode {
public init?(character: String) {
if let keyCode = Initializers.shared.characterKeys[character] {
self = keyCode
} else {
return nil
}
}
public init?(modifierFlag: NSEvent.ModifierFlags) {
if let keyCode = Initializers.shared.modifierFlagKeys[modifierFlag] {
self = keyCode
} else {
return nil
}
}
public init?(specialKey: NSEvent.SpecialKey) {
if let keyCode = Initializers.shared.specialKeys[specialKey] {
self = keyCode
} else {
return nil
}
}
private struct Initializers {
let specialKeys: [NSEvent.SpecialKey:CGKeyCode]
let characterKeys: [String:CGKeyCode]
let modifierFlagKeys: [NSEvent.ModifierFlags:CGKeyCode]
static let shared = Initializers()
init() {
var specialKeys = [NSEvent.SpecialKey:CGKeyCode]()
var characterKeys = [String:CGKeyCode]()
var modifierFlagKeys = [NSEvent.ModifierFlags:CGKeyCode]()
for keyCode in (0..<128).map({ CGKeyCode($0) }) {
guard let cgevent = CGEvent(keyboardEventSource: nil, virtualKey: CGKeyCode(keyCode), keyDown: true) else { continue }
guard let nsevent = NSEvent(cgEvent: cgevent) else { continue }
var hasHandledKeyCode = false
if nsevent.type == .keyDown {
if let specialKey = nsevent.specialKey {
hasHandledKeyCode = true
specialKeys[specialKey] = keyCode
} else if let characters = nsevent.charactersIgnoringModifiers, !characters.isEmpty && characters != "\u{0010}" {
hasHandledKeyCode = true
characterKeys[characters] = keyCode
}
} else if nsevent.type == .flagsChanged, let modifierFlag = nsevent.modifierFlags.first(.capsLock, .shift, .control, .option, .command, .help, .function) {
hasHandledKeyCode = true
modifierFlagKeys[modifierFlag] = keyCode
}
if !hasHandledKeyCode {
#if DEBUG
print("Unhandled keycode \(keyCode): \(nsevent)")
#endif
}
}
self.specialKeys = specialKeys
self.characterKeys = characterKeys
self.modifierFlagKeys = modifierFlagKeys
}
}
}
extension NSEvent.ModifierFlags: Hashable { }
extension OptionSet {
public func first(_ options: Self.Element ...) -> Self.Element? {
for option in options {
if contains(option) {
return option
}
}
return nil
}
}
Die Dokumentation sagt, dass der Wert für kTISPropertyUnicodeKeyLayoutData ist ein CFDataRef, also ist diese Besetzung richtig. Der Fehler hat nichts mit Qt zu tun; es wird stattdessen durch Ihre Einstellungen (wie paranoid Sie den Compiler konfiguriert haben) oder die Wahl der Sprache (I denken Es ist wahrscheinlicher, dass Sie diesen Fehler in C++ erhalten, aber ich könnte mich irren und kenne keine Einzelheiten).
– Peter Hosey
3. Januar 2013 um 23:22 Uhr
13893400cookie-checkWie konvertiere ich ASCII-Zeichen in CGKeyCode?yes
@Sneakyness: Ich möchte die Schlüsselkonstanten nicht fest codieren. Sie werden a.) durch Benutzereingaben generiert und b.) können das Ergebnis mehrerer Tastaturlayouts sein.
– Michael
28. Dezember 2009 um 1:01 Uhr
@Michael – Hast du die funktionierende Version des Keyloggers bekommen? Ich suche einen. Ich habe einige Git-Pakete ausprobiert. Funktioniert aber nicht wie erwartet/ erfasst nicht alle Tastenanschläge. Oder haben Sie hierzu Vorschläge? Irgendwelche Open-Source-Pakete? Es wäre sehr hilfreich
– Dany
4. März 2016 um 4:37 Uhr