2012-05-24 17 views
11

Potrzebuję symulować naciśnięcia klawiszy w systemie OSX. Oto jak to zrobić:Symulowanie naciśnięcia klawiszy skrótu systemowego

-(void)execute { 
    CGEventSourceRef sourceRef = 
    CGEventSourceCreate(kCGEventSourceStateHIDSystemState); 

    CGEventRef keyPress = CGEventCreateKeyboardEvent (sourceRef, (CGKeyCode)keyCode, true); 
    CGEventRef keyUnpress = CGEventCreateKeyboardEvent (sourceRef, (CGKeyCode)keyCode, false); 

    CGEventSetFlags(keyPress, modifierFlags); 
    CGEventPost(kCGHIDEventTap, keyPress); 

    //unpressing the acualkey 
    CGEventPost(kCGHIDEventTap, keyUnpress); 

    CFRelease(keyPress); 
    CFRelease(keyUnpress); 
    CFRelease(sourceRef); 
} 

To działa dobrze dla każdego skrótu lub prostych naciśnięć klawiszy w dowolnej aplikacji, ale nie działa na systemie szerokich skróty, na przykład Option + przestrzeń uruchomić Spotlight lub cmd + shift + 4, aby zrobić zrzut ekranu lub ctrl + `, aby otworzyć okno iTerm2.

Próbowałem zmienić źródło wydarzenia i miejsce, w którym publikuję wydarzenie, nie pomaga. Jakieś pomysły?

Odpowiedz

16

Z dokumentacji CGEventCreateKeyboardEvent:

wszystkie naciśnięcia klawiszy potrzebne do wygenerowania charakter muszą być wprowadzone, w tym klawiszy modyfikujących. Na przykład, aby wygenerować "Z", klawisz SHIFT musi być wciśnięty, klawisz "z" musi obniżyć się, a następnie klawisz SHIFT i "z" musi zostać zwolniony:

Dzięki temu można " t po prostu naciśnij i zwolnij miejsce za pomocą modyfikatora opcji, aby wywołać pole opcji; musisz nacisnąć opcję, naciśnij spację, zwolnij miejsce, zwolnij opcję.

Na marginesie, opt-space nic nie robi domyślnie; cmd-space jest skrótem wyszukiwania Spotlight, a cmd-opt-space jest skrótem okna Spotlight.

Tak, ten kod pojawi się wyszukiwanie Spotlight:

- (void)execute { 
    CGEventSourceRef src = 
    CGEventSourceCreate(kCGEventSourceStateHIDSystemState); 

    CGEventRef cmdd = CGEventCreateKeyboardEvent(src, 0x38, true); 
    CGEventRef cmdu = CGEventCreateKeyboardEvent(src, 0x38, false); 
    CGEventRef spcd = CGEventCreateKeyboardEvent(src, 0x31, true); 
    CGEventRef spcu = CGEventCreateKeyboardEvent(src, 0x31, false); 

    CGEventSetFlags(spcd, kCGEventFlagMaskCommand); 
    CGEventSetFlags(spcu, kCGEventFlagMaskCommand); 

    CGEventTapLocation loc = kCGHIDEventTap; // kCGSessionEventTap also works 
    CGEventPost(loc, cmdd); 
    CGEventPost(loc, spcd); 
    CGEventPost(loc, spcu); 
    CGEventPost(loc, cmdu); 

    CFRelease(cmdd); 
    CFRelease(cmdu); 
    CFRelease(spcd); 
    CFRelease(spcu); 
    CFRelease(src); 
} 
+0

Działa, dzięki. Na początku użyłem podobnego kodu, ale z jakiegoś powodu nie zadziałało. –

+0

P.S: Na non my Macs cmd + spacja służy domyślnie do zmiany układu klawiatury. –

+0

Istnieje wiele małych dziwactw dotyczących publikowania wydarzeń na klawiaturze, a czasami trzeba zrobić trochę prób i błędów, aby uzyskać coś, co działa tak, jak chcesz. W tym konkretnym przypadku, dokumentacja opisuje dokładnie to, co robiłeś źle, ale to jest całkiem rzadkie ... – abarnert

4

Dla przypomnienia, podczas gdy użytkownika @ abarnert odpowiedź jest wielki i to jest sposób należy to zrobić zgodnie z dokumentacją, mój oryginalny kod działa również. Odkryłem, że mam inny problem, niezwiązany z tym pytaniem.

Tak więc, jeśli chcesz zastosować klawisze modyfikujące do naciśnięcia klawisza, możesz po prostu dodać je w ten sposób CGEventSetFlags(keyPress, modifierFlags); bez naciskania osobnego przyciśnięcia każdego klawisza modyfikującego. Takie podejście działa, a ja nie znalazłem jeszcze żadnych wad, a czytelność kodu jest znacznie lepsza.

7

Dla każdego, kto chce mieć listę CGKeyCode, jest tutaj funkcja z the RUI project z częściową tabelą.

Chociaż this może być pełniejszym przykładem. Ktoś wie o bardziej kompletnej mapie?

int keyCodeForKeyString(char * keyString); // get the Mac keycode for the RUI representation 

int keyCodeForKeyString(char * keyString) 
{ 
    if (strcmp(keyString, "a") == 0) return 0; 
    if (strcmp(keyString, "s") == 0) return 1; 
    if (strcmp(keyString, "d") == 0) return 2; 
    if (strcmp(keyString, "f") == 0) return 3; 
    if (strcmp(keyString, "h") == 0) return 4; 
    if (strcmp(keyString, "g") == 0) return 5; 
    if (strcmp(keyString, "z") == 0) return 6; 
    if (strcmp(keyString, "x") == 0) return 7; 
    if (strcmp(keyString, "c") == 0) return 8; 
    if (strcmp(keyString, "v") == 0) return 9; 
    // what is 10? 
    if (strcmp(keyString, "b") == 0) return 11; 
    if (strcmp(keyString, "q") == 0) return 12; 
    if (strcmp(keyString, "w") == 0) return 13; 
    if (strcmp(keyString, "e") == 0) return 14; 
    if (strcmp(keyString, "r") == 0) return 15; 
    if (strcmp(keyString, "y") == 0) return 16; 
    if (strcmp(keyString, "t") == 0) return 17; 
    if (strcmp(keyString, "1") == 0) return 18; 
    if (strcmp(keyString, "2") == 0) return 19; 
    if (strcmp(keyString, "3") == 0) return 20; 
    if (strcmp(keyString, "4") == 0) return 21; 
    if (strcmp(keyString, "6") == 0) return 22; 
    if (strcmp(keyString, "5") == 0) return 23; 
    if (strcmp(keyString, "=") == 0) return 24; 
    if (strcmp(keyString, "9") == 0) return 25; 
    if (strcmp(keyString, "7") == 0) return 26; 
    if (strcmp(keyString, "-") == 0) return 27; 
    if (strcmp(keyString, "8") == 0) return 28; 
    if (strcmp(keyString, "0") == 0) return 29; 
    if (strcmp(keyString, "]") == 0) return 30; 
    if (strcmp(keyString, "o") == 0) return 31; 
    if (strcmp(keyString, "u") == 0) return 32; 
    if (strcmp(keyString, "[") == 0) return 33; 
    if (strcmp(keyString, "i") == 0) return 34; 
    if (strcmp(keyString, "p") == 0) return 35; 
    if (strcmp(keyString, "RETURN") == 0) return 36; 
    if (strcmp(keyString, "l") == 0) return 37; 
    if (strcmp(keyString, "j") == 0) return 38; 
    if (strcmp(keyString, "'") == 0) return 39; 
    if (strcmp(keyString, "k") == 0) return 40; 
    if (strcmp(keyString, ";") == 0) return 41; 
    if (strcmp(keyString, "\\") == 0) return 42; 
    if (strcmp(keyString, ",") == 0) return 43; 
    if (strcmp(keyString, "/") == 0) return 44; 
    if (strcmp(keyString, "n") == 0) return 45; 
    if (strcmp(keyString, "m") == 0) return 46; 
    if (strcmp(keyString, ".") == 0) return 47; 
    if (strcmp(keyString, "TAB") == 0) return 48; 
    if (strcmp(keyString, "SPACE") == 0) return 49; 
    if (strcmp(keyString, "`") == 0) return 50; 
    if (strcmp(keyString, "DELETE") == 0) return 51; 
    if (strcmp(keyString, "ENTER") == 0) return 52; 
    if (strcmp(keyString, "ESCAPE") == 0) 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 (strcmp(keyString, ".") == 0) return 65; 

    if (strcmp(keyString, "*") == 0) return 67; 

    if (strcmp(keyString, "+") == 0) return 69; 

    if (strcmp(keyString, "CLEAR") == 0) return 71; 

    if (strcmp(keyString, "/") == 0) return 75; 
    if (strcmp(keyString, "ENTER") == 0) return 76; // numberpad on full kbd 

    if (strcmp(keyString, "=") == 0) return 78; 

    if (strcmp(keyString, "=") == 0) return 81; 
    if (strcmp(keyString, "0") == 0) return 82; 
    if (strcmp(keyString, "1") == 0) return 83; 
    if (strcmp(keyString, "2") == 0) return 84; 
    if (strcmp(keyString, "3") == 0) return 85; 
    if (strcmp(keyString, "4") == 0) return 86; 
    if (strcmp(keyString, "5") == 0) return 87; 
    if (strcmp(keyString, "6") == 0) return 88; 
    if (strcmp(keyString, "7") == 0) return 89; 

    if (strcmp(keyString, "8") == 0) return 91; 
    if (strcmp(keyString, "9") == 0) return 92; 

    if (strcmp(keyString, "F5") == 0) return 96; 
    if (strcmp(keyString, "F6") == 0) return 97; 
    if (strcmp(keyString, "F7") == 0) return 98; 
    if (strcmp(keyString, "F3") == 0) return 99; 
    if (strcmp(keyString, "F8") == 0) return 100; 
    if (strcmp(keyString, "F9") == 0) return 101; 

    if (strcmp(keyString, "F11") == 0) return 103; 

    if (strcmp(keyString, "F13") == 0) return 105; 

    if (strcmp(keyString, "F14") == 0) return 107; 

    if (strcmp(keyString, "F10") == 0) return 109; 

    if (strcmp(keyString, "F12") == 0) return 111; 

    if (strcmp(keyString, "F15") == 0) return 113; 
    if (strcmp(keyString, "HELP") == 0) return 114; 
    if (strcmp(keyString, "HOME") == 0) return 115; 
    if (strcmp(keyString, "PGUP") == 0) return 116; 
    if (strcmp(keyString, "DELETE") == 0) return 117; 
    if (strcmp(keyString, "F4") == 0) return 118; 
    if (strcmp(keyString, "END") == 0) return 119; 
    if (strcmp(keyString, "F2") == 0) return 120; 
    if (strcmp(keyString, "PGDN") == 0) return 121; 
    if (strcmp(keyString, "F1") == 0) return 122; 
    if (strcmp(keyString, "LEFT") == 0) return 123; 
    if (strcmp(keyString, "RIGHT") == 0) return 124; 
    if (strcmp(keyString, "DOWN") == 0) return 125; 
    if (strcmp(keyString, "UP") == 0) return 126; 

    fprintf(stderr, "keyString %s Not Found. Aborting...\n", keyString); 
    exit(EXIT_FAILURE); 
} 
+0

Czy to nie układ klawiatury? Podobnie jak w przypadku US Keyboard i jeśli używasz tego na przykład w niemieckim układzie klawiatury ustawionym w OS X, niż będzie to nieprawidłowe? –

0

XCode 7,3 Swift 2.2:

let event1 = CGEventCreateKeyboardEvent(nil, 0x09, true); // cmd-v down 
CGEventSetFlags(event1, CGEventFlags.MaskCommand); 
CGEventPost(CGEventTapLocation.CGHIDEventTap, event1); 

let event2 = CGEventCreateKeyboardEvent(nil, 0x09, false); // cmd-v up 
CGEventSetFlags(event2, CGEventFlags.MaskCommand); 
CGEventPost(CGEventTapLocation.CGHIDEventTap, event2); 

kod powyżej symuluje CMD-V wciśnięty następnie zwolniony (aka: pasta).

+0

Należy zauważyć, że istnieje przykład Swift3 [http://stackoverflow.com/questions/27484330/simulate-keypress-using-swift](http://stackoverflow.com/questions/27484330/simulate-keypress-using-swift) –

Powiązane problemy