371273
371273

Reputation: 5446

How to convert a string into a series of keystrokes?

I'm using CGPostKeyboardEvent((CGCharCode)0, (CGKeyCode)55, true); to simulate key presses, but say I had a string that I wanted to convert to key presses. How would I go about dividing an NSString up into single characters, and then converting those into key presses? Thanks!

Edit: OK I think I found a solution, but I am unable to get my syntax right. Objective-C really drives me crazy.

Here's my code:

int stringLength = [theData length];
  for (int i = 1; i <= stringLength; i++) {
   char *currentCharacter = [theData characterAtIndex:i];
   CGPostKeyboardEvent((CGCharCode)0, (CGKeyCode)keyCodeForKeyString(currentCharacter), true);
}

-(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;

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

So my question is, How do I get the keyCodeForKeyString(currentCharacter) inside the argument of CGPostKeyboardEvent?

Upvotes: 1

Views: 1745

Answers (2)

Dave DeLong
Dave DeLong

Reputation: 243156

This can be a difficult problem, but not for the reason that @JWWalker states.

If you can easily convert keycodes to characters, then it is trivial to convert from a character to a keycode. It's a 1-to-1 mapping between the two (a character has a single keycode, and a keycode has a single [sometimes non-printable] character), so you can easily build the transformation yourself. The ShortcutRecorder project has an NSValueTransformer subclass that does this.

The difficulty is that posting keystrokes does not always result in a synchronous action. Since you're (essentially) communicating to another process, you have no idea how long that process will take to handle your event posts and perform the appropriate action. The time between "posting" and "handling" is indeterminate based on the current load and activity on the system. Usually it happens fairly quickly (and in such a way as to appear mostly synchronous), but it doesn't have to be. My particular example comes from dealing with the pasteboard server, which sometimes takes its very sweet time to respond to a cmd-v keystroke.

If all you're doing is mimicking typing, then that shouldn't be too bad. You can get the char* of your string using -[NSString UTF8String] (or similar), then simply loop through the characters, convert them to keycodes, and post the appropriate events.

Upvotes: 2

JWWalker
JWWalker

Reputation: 22717

That problem is a nightmare, because there are functions to translate key codes to character codes, but not the other way around. Remember that not all characters can be typed, and which ones can be typed depends on the current keyboard layout.

If your goal is to make some text appear in another application, you may be able to do it without translating individual characters by using CGEventKeyboardSetUnicodeString. However, implementation of this feature has been spotty, so be sure to test on all OS versions you care about, and in both Carbon and Cocoa apps.

Upvotes: 3

Related Questions