Keystrokes for non-ascii letters
-
Hey everyone,
I'm working on a client/server application. The client sends tiny
"Event" objects to the server that can contain an NSString of a letter
or short sequence of letters (up to about 4). What I'm trying to do
is figure out how the server can perform the keypress(es) to get that
letter (or sequence).
I know that I could use CGEventCreateKeyboardEvent, but that requires
me to know the precise keycode for the letter. If I were limited to
just ASCII 0-127, that wouldn't be so bad. But I could also be
getting things like "é" or "£" and so on. I'd rather not hard code in
every keystroke combination. =)
Alternatively, I could try using AppleScript. But in playing around
with it, I found that if I do: Tell app "System Events" to keystroke
"é", then all it does is type "a". Other tests have shown that the
"keystroke" command only accepts basic ASCII characters. Of course I
could use the "using command down" to get the non-ascii letters, but
again, that would require me to hard code in every keystroke
combination.
My last idea is to put it on the clipboard and paste it in by
simulating a command-v keystroke. The only problem with this is that
command-v doesn't mean paste on all keyboards.
Do any of you have any ideas on how I can type arbitrary UTF8
characters programmatically?
Thanks,
Dave -
On Nov 29, 2008, at 8:26 AM, Dave DeLong wrote:
> Hey everyone,
>
> I'm working on a client/server application. The client sends tiny
> "Event" objects to the server that can contain an NSString of a
> letter or short sequence of letters (up to about 4). What I'm
> trying to do is figure out how the server can perform the
> keypress(es) to get that letter (or sequence).
>
> I know that I could use CGEventCreateKeyboardEvent, but that
> requires me to know the precise keycode for the letter. If I were
> limited to just ASCII 0-127, that wouldn't be so bad. But I could
> also be getting things like "é" or "£" and so on. I'd rather not
> hard code in every keystroke combination. =)
In general, this is difficult, because keyboard translation occurs via
a semi-programmable state machine (the 'uchr' resource). So
effectively you either need to run the state machine backwards, or
start with each possible input keycode and modifiers combination, run
the state machine forwards to produce the output character and use
that to generate a table of what inputs produce what outputs.
> My last idea is to put it on the clipboard and paste it in by
> simulating a command-v keystroke. The only problem with this is
> that command-v doesn't mean paste on all keyboards.
>
> Do any of you have any ideas on how I can type arbitrary UTF8
> characters programmatically?
You might look at CGKeyboardEventSetUnicodeString, although that won't
help you to simulate command key sequences, because you can't set
modifiers using that API.
You might also look at using the Accessibility API to explicit select
the Paste menu item, rather than trying to simulate a keypress that
would invoke the Paste menu item.
-eric -
On Nov 29, 2008, at 10:26 AM, Dave DeLong wrote:
> I'm working on a client/server application. The client sends tiny
> "Event" objects to the server that can contain an NSString of a
> letter or short sequence of letters (up to about 4). What I'm
> trying to do is figure out how the server can perform the
> keypress(es) to get that letter (or sequence).
>
> I know that I could use CGEventCreateKeyboardEvent, but that
> requires me to know the precise keycode for the letter. If I were
> limited to just ASCII 0-127, that wouldn't be so bad. But I could
> also be getting things like "é" or "£" and so on. I'd rather not
> hard code in every keystroke combination. =)
>
> Alternatively, I could try using AppleScript. But in playing around
> with it, I found that if I do: Tell app "System Events" to
> keystroke "é", then all it does is type "a". Other tests have shown
> that the "keystroke" command only accepts basic ASCII characters.
> Of course I could use the "using command down" to get the non-ascii
> letters, but again, that would require me to hard code in every
> keystroke combination.
>
> My last idea is to put it on the clipboard and paste it in by
> simulating a command-v keystroke. The only problem with this is
> that command-v doesn't mean paste on all keyboards.
>
> Do any of you have any ideas on how I can type arbitrary UTF8
> characters programmatically?
As part of an automated testing framework, I generate individual
Unicode keyboard events like this:
- (void)postUnicodeKeyboardEvent_II:(unichar)aUnicodeCharacter
{
unichar theCharacters[1];
theCharacters[0] = aUnicodeCharacter;
NSString* theString = [[NSString alloc]
initWithCharacters:theCharacters length:1];
int theWindowNumber = [[applicationController_II contentWindow_II]
windowNumber];
NSEvent* theKeyboardEvent =
[NSEvent keyEventWithType:NSKeyDown location:NSMakePoint (0, 0)
modifierFlags:0 timestamp:0
windowNumber:theWindowNumber context:nil
characters:theString charactersIgnoringModifiers:nil
isARepeat:NO keyCode:0];
[NSApp postEvent:theKeyboardEvent atStart:NO];
}
In my case, I never needed to set the modifier flags, but you can
easily pass in whatever you need to above. And, depending on what
modifiers you're working with, make sure to properly set the
charactersIgnoringModifiers: param as well.
___________________________________________________________
Ricky A. Sharp mailto:<rsharp...>
Instant Interactive(tm) http://www.instantinteractive.com -
An off-list reply pointed this one out to me as well, and I've been
playing with it. But I have some more roadblocks:
My server app is an agent application (it only runs from the
menubar). My preliminary tests show that posting keyboard events this
way to another application only result in a system beep. Of course,
that beep might be because I have the windowNumber hard set to 0.
When it's my own application that receives the event (I have a
textfield that's first responder), then it works perfectly.
So my questions are:
Can this be used for posting events that would get picked up by other
applications?
If it can, what should I do for the windowNumber?
Thanks a bunch,
Dave
On 29 Nov, 2008, at 10:41 AM, Ricky Sharp wrote:
> As part of an automated testing framework, I generate individual
> Unicode keyboard events like this:
>
> - (void)postUnicodeKeyboardEvent_II:(unichar)aUnicodeCharacter
> {
> unichar theCharacters[1];
>
> theCharacters[0] = aUnicodeCharacter;
> NSString* theString = [[NSString alloc]
> initWithCharacters:theCharacters length:1];
>
> int theWindowNumber = [[applicationController_II contentWindow_II]
> windowNumber];
>
> NSEvent* theKeyboardEvent =
> [NSEvent keyEventWithType:NSKeyDown location:NSMakePoint (0, 0)
> modifierFlags:0 timestamp:0
> windowNumber:theWindowNumber context:nil
> characters:theString charactersIgnoringModifiers:nil
> isARepeat:NO keyCode:0];
>
> [NSApp postEvent:theKeyboardEvent atStart:NO];
> }
>
> In my case, I never needed to set the modifier flags, but you can
> easily pass in whatever you need to above. And, depending on what
> modifiers you're working with, make sure to properly set the
> charactersIgnoringModifiers: param as well.
-
On Nov 29, 2008, at 10:00 AM, Dave DeLong wrote:
> Can this be used for posting events that would get picked up by
> other applications?
Nope.
To be honest, I don't know how you post such events to another
application -- specifically targeted to another application. In
general, Mac OS X maintains a notion of a active application. The
[there can only be one] active application is the one to which all
keyboard events are directed, save for system hot-key type key
events. While, certainly, mouse events can be directed to other
applications, any kind of a click event is generally also going to
cause the active application to change.
You have mentioned "server" application. Do you have a specific
client application you are targeting? Or are you trying to
generically send key events to various apps on the system?
b.bum -
The client application is running on an iPhone/iPod touch and is
sending events to the server, which runs (as I mentioned) as an agent
application on the desktop. I'm writing both.
The purpose of the server application is to dispatch events to the
system. These can be many different kinds of events, and right now
I'm working on getting the key events to dispatch properly. If I have
a keycode, I can successfully use CGEventCreateKeyboardEvent to create
and dispatch hard coded keystrokes.
My goal now is to accept arbitrary strings and post the keyboard
events for them. For ASCII characters, I can easily dispatch a
CGEventRef. However, I want to be able to send non-ascii characters
as well. Basically, any character that's valid on the iPhone I want
to be able to mimic on the desktop. So this includes things like £,
but also Asian characters that are inputted via the drawing keyboard.
Any ideas how I could go about this?
Thanks,
Dave
On 29 Nov, 2008, at 11:34 AM, Bill Bumgarner wrote:
> On Nov 29, 2008, at 10:00 AM, Dave DeLong wrote:
>> Can this be used for posting events that would get picked up by
>> other applications?
>
> Nope.
>
> To be honest, I don't know how you post such events to another
> application -- specifically targeted to another application. In
> general, Mac OS X maintains a notion of a active application. The
> [there can only be one] active application is the one to which all
> keyboard events are directed, save for system hot-key type key
> events. While, certainly, mouse events can be directed to other
> applications, any kind of a click event is generally also going to
> cause the active application to change.
>
> You have mentioned "server" application. Do you have a specific
> client application you are targeting? Or are you trying to
> generically send key events to various apps on the system?
>
> b.bum
-
Le 29 nov. 08 à 19:34, Bill Bumgarner a écrit :
> On Nov 29, 2008, at 10:00 AM, Dave DeLong wrote:
>> Can this be used for posting events that would get picked up by
>> other applications?
>
> Nope.
>
> To be honest, I don't know how you post such events to another
> application -- specifically targeted to another application.
CGEventPostToPSN() ? OK, it does not works with NSEvent, but it allows
you to specify the target application of a CGEvent.
> In general, Mac OS X maintains a notion of a active application.
> The [there can only be one] active application is the one to which
> all keyboard events are directed, save for system hot-key type key
> events. While, certainly, mouse events can be directed to other
> applications, any kind of a click event is generally also going to
> cause the active application to change.
>
> You have mentioned "server" application. Do you have a specific
> client application you are targeting? Or are you trying to
> generically send key events to various apps on the system?
>
> b.bum
-
On Nov 29, 2008, at 10:48 AM, Dave DeLong wrote:
> My goal now is to accept arbitrary strings and post the keyboard
> events for them. For ASCII characters, I can easily dispatch a
> CGEventRef. However, I want to be able to send non-ascii characters
> as well. Basically, any character that's valid on the iPhone I want
> to be able to mimic on the desktop. So this includes things like £,
> but also Asian characters that are inputted via the drawing keyboard.
Eric Schlegel already suggested CGEventKeyboardSetUnicodeString,
although he misspelled it. As long as you can require 10.5.5 or
later, that should do the trick. -
More questions! (wheeee =) )
I've abandoned the NSEvent approach, although it would've been nice if
it had worked, and am now trying CGEventKeyboardSetUnicodeString.
Here's my code:
CGEventSourceRef eventSource =
CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
CGEventRef keyEventDown = CGEventCreateKeyboardEvent(eventSource, 0,
true);
UniChar buffer = '£'; //that's a pound (the currency) sign for all
you without unicode support in your email
CGEventKeyboardSetUnicodeString(keyEventDown, 1, &buffer);
CGEventPost(kCGHIDEventTap, keyEventDown);
CFRelease(keyEventDown);
First off, when building it, I get a warning on the "buffer = '£';"
line, that it's a "multi-character character constant". What does
that mean? Then, when I actually run it, I don't get the pound sign,
but get some Asian character that looks like a cross between a camping
stove and a two-story house. Lastly, I'm not sure how I can convert
my NSString into a UniChar array (which is what the function wants).
I've been all over Google and the various list archives for more
information on CGEventKeyboardSetUnicodeString, but have found nothing
helpful.
Can anyone point me in the right direction?
Thanks for all your help!
Dave
On 29 Nov, 2008, at 1:27 PM, James W. Walker wrote:
> Eric Schlegel already suggested CGEventKeyboardSetUnicodeString,
> although he misspelled it. As long as you can require 10.5.5 or
> later, that should do the trick.
-
On Nov 29, 2008, at 1:03 PM, Dave DeLong wrote:
> More questions! (wheeee =) )
>
> I've abandoned the NSEvent approach, although it would've been nice
> if it had worked, and am now trying
> CGEventKeyboardSetUnicodeString. Here's my code:
>
> CGEventSourceRef eventSource =
> CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
> CGEventRef keyEventDown = CGEventCreateKeyboardEvent(eventSource,
> 0, true);
> UniChar buffer = '£'; //that's a pound (the currency) sign for all
> you without unicode support in your email
> CGEventKeyboardSetUnicodeString(keyEventDown, 1, &buffer);
> CGEventPost(kCGHIDEventTap, keyEventDown);
> CFRelease(keyEventDown);
>
> First off, when building it, I get a warning on the "buffer = '£';"
> line, that it's a "multi-character character constant". What does
> that mean? Then, when I actually run it, I don't get the pound
> sign, but get some Asian character that looks like a cross between a
> camping stove and a two-story house.
Your source file is probably encoded as UTF-8, so the pound character
is getting interpreted as 2 bytes of UTF-8, not a single UTF-16
character. Don't try to enter Unicode directly in your source.
> Lastly, I'm not sure how I can convert my NSString into a UniChar
> array (which is what the function wants).
See the getCharacters: method.
> I've been all over Google and the various list archives for more
> information on CGEventKeyboardSetUnicodeString, but have found
> nothing helpful.
It didn't actually work for both Cocoa and Carbon apps until some
recent update of Leopard, so probably nobody has been using it.
> On 29 Nov, 2008, at 1:27 PM, James W. Walker wrote:
>
>> Eric Schlegel already suggested CGEventKeyboardSetUnicodeString,
>> although he misspelled it. As long as you can require 10.5.5 or
>> later, that should do the trick.
-
Fantastic! I've gotten it to work, and it works beautifully! Thank
you, James (and everyone else) for helping me with this.
For archival purposes, here's my code:
CGEventSourceRef eventSource =
CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
CGEventRef keyEventDown = CGEventCreateKeyboardEvent(eventSource, 0,
true);
NSString * characters = ;//some UTF16 string acquired from
somewhere. in my case, an NSData object
UniChar buffer;
for (int i = 0; i < [characters length]; i++) {
[characters getCharacters:&buffer range:NSMakeRange(i, 1)];
keyEventDown = CGEventCreateKeyboardEvent(eventSource, 1, true);
CGEventKeyboardSetUnicodeString(keyEventDown, 1, &buffer);
CGEventPost(kCGHIDEventTap, keyEventDown);
CFRelease(keyEventDown);
}
CFRelease(eventSource);
Thanks again for all your help!
Dave
On 29 Nov, 2008, at 3:10 PM, James W. Walker wrote:
> Your source file is probably encoded as UTF-8, so the pound
> character is getting interpreted as 2 bytes of UTF-8, not a single
> UTF-16 character. Don't try to enter Unicode directly in your source.
>
>> Lastly, I'm not sure how I can convert my NSString into a UniChar
>> array (which is what the function wants).
>
> See the getCharacters: method.
-
Le 30 nov. 08 à 01:02, Dave DeLong a écrit :
> Fantastic! I've gotten it to work, and it works beautifully! Thank
> you, James (and everyone else) for helping me with this.
>
> For archival purposes, here's my code:
>
> CGEventSourceRef eventSource =
> CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
> CGEventRef keyEventDown = CGEventCreateKeyboardEvent(eventSource,
> 0, true);
> NSString * characters = ;//some UTF16 string acquired from
> somewhere. in my case, an NSData object
> UniChar buffer;
> for (int i = 0; i < [characters length]; i++) {
> [characters getCharacters:&buffer range:NSMakeRange(i, 1)];
> keyEventDown = CGEventCreateKeyboardEvent(eventSource, 1, true);
> CGEventKeyboardSetUnicodeString(keyEventDown, 1, &buffer);
> CGEventPost(kCGHIDEventTap, keyEventDown);
> CFRelease(keyEventDown);
> }
> CFRelease(eventSource);
>
> Thanks again for all your help!
>
> Dave
Just a detail, but you may prefere -[NSString characterAtIndex:]
instead of -[NSString getCharacters:buffer:]



